Loading...

Day 2:基礎配置 —— 你的第一次 `configuration.nix` 編輯

手把手帶你編輯第一份 configuration.nix,學會安裝套件、管理使用者與開啟 SSH 服務,並透過 nixos-rebuild 讓配置生效。

Day 2:基礎配置 —— 你的第一次 configuration.nix 編輯

🗓 系列:NixOS 30 天學習之旅
📦 階段:第一階段 — 基礎與生存守則 (Day 1 – Day 7)
🎯 階段核心目標:理解 Declarative 配置與不可變性


環境說明

🖥 本系列文章的操作情境如下:

  • 遠端 NixOS server(純 CLI,無 GUI、無桌面環境)——所有涉及 configuration.nixnixos-rebuild 的操作,都是透過 SSH 連線到這台 server 上執行。
  • 本地 MacBook(macOS + CLI/GUI)——日常開發機器,使用 nix-darwin + Home Manager 管理本地環境,不會有 /etc/nixos/configuration.nix

換句話說,當文章提到「打開 configuration.nix」或「執行 sudo nixos-rebuild switch」,指的都是在遠端 NixOS server 上的操作。如果你跟我一樣是用 MacBook SSH 進 NixOS server,請先確認 SSH 連線正常再繼續。


前言

在 Day 1,我們完成了 NixOS 的安裝,初步認識了這個與眾不同的 Linux distribution。你可能已經感受到,NixOS 的世界裡沒有 apt install、沒有 yum,一切都圍繞著一個核心檔案運轉——/etc/nixos/configuration.nix

今天,我們要正式打開這個檔案,學會三件最基本也最實用的事:

  1. 安裝系統套件environment.systemPackages
  2. 管理使用者帳號users.users
  3. 開啟 SSH 服務services.openssh

學完這三招,你就能在 NixOS 上自由地安裝軟體、建立使用者,並確保 SSH 連線設定完善。走吧!


configuration.nix 的結構解析

SSH 進你的 NixOS server 後,用 sudo nano /etc/nixos/configuration.nix(或你偏好的 editor)打開這個檔案。你會看到類似以下的結構:

💡 MacBook 使用者提示:從你的 MacBook 終端機執行 ssh user@your-nixos-server-ip,連線成功後再進行以下操作。本地的 MacBook 上不會有這個檔案——那是 NixOS 專屬的系統配置。

# /etc/nixos/configuration.nix
{ config, pkgs, ... }:

{
  imports =
    [ ./hardware-configuration.nix ];

  # Bootloader 設定
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  # 網路
  networking.hostName = "my-nixos";

  # 時區
  time.timeZone = "Asia/Taipei";

  # 系統套件
  environment.systemPackages = with pkgs; [
    vim
    wget
  ];

  # 系統版本(請勿隨意更動)
  system.stateVersion = "24.05";
}

幾個重點觀念

語法元素說明
{ config, pkgs, ... }:這是一個 Nix function,接收 config(系統配置)和 pkgs(套件集合)作為參數
imports = [ ... ];引入其他 .nix 檔案,hardware-configuration.nix 是安裝時自動產生的硬體設定
attribute = value;Nix 的基本 key-value 設定方式,每行結尾用分號 ;
with pkgs; [ ... ]語法糖,讓你在 list 裡直接寫套件名稱,不需要每個都加上 pkgs. 前綴

💡 小提醒configuration.nix 本質上是一個 Nix expression,它是一個 function,回傳一個 attribute set。這也是為什麼最外層是 { ... }: 搭配 { ... } 的結構。


安裝系統套件(environment.systemPackages

在 NixOS 上安裝套件,不是下指令,而是寫配置。找到 environment.systemPackages 這個區塊,把你需要的套件加進去:

environment.systemPackages = with pkgs; [
  vim
  wget
  curl
  git
  htop
  tmux
  unzip
];

怎麼找套件名稱?

你可能會問:「我怎麼知道套件在 Nix 裡面叫什麼名字?」有幾個方法:

方法一:用 nix search 指令

# 搜尋含有 "firefox" 的套件
nix search nixpkgs firefox

方法二:到 Nix Packages 搜尋網站

前往 search.nixos.org ,在網頁上直接搜尋,這是最直覺的方式。

方法三:用 nix-env -qaP 查詢(傳統方式)

nix-env -qaP | grep firefox

💡 小提醒environment.systemPackages 安裝的套件是 system-wide 的,所有使用者都能使用。如果你只想讓特定使用者安裝套件,Day 後面的章節會介紹 home-manager,敬請期待。


使用者管理(users.users

NixOS 的使用者管理同樣是 declarative 的。你不會用 useradd 指令來建立使用者,而是在 configuration.nix 中宣告:

users.users.james = {
  isNormalUser = true;
  description = "James Hsueh";
  home = "/home/james";
  extraGroups = [ "wheel" "networkmanager" "docker" ];
  shell = pkgs.zsh;
};

各欄位說明

欄位說明
isNormalUser設為 true 表示這是一般使用者(非系統帳號),會自動建立 home 目錄
description使用者的全名或描述
home指定 home 目錄路徑
extraGroups額外加入的群組。wheel 可以使用 sudonetworkmanager 可管理網路
shell指定預設 shell,注意這裡用的是 pkgs.zsh,所以要確保 zsh 有安裝

設定密碼

第一次建立使用者後,需要用 passwd 指令來設定密碼:

sudo passwd james

如果你想要在配置中指定 hashed password(適合自動化佈署情境),可以這樣做:

# 先產生 hashed password
mkpasswd -m sha-512
users.users.james = {
  isNormalUser = true;
  description = "James Hsueh";
  extraGroups = [ "wheel" "networkmanager" ];
  hashedPassword = "$6$xxxxxxx...";  # mkpasswd 產生的 hash
};

⚠️ 安全提醒:如果你把 configuration.nix 放進 Git repository 管理(這是好習慣!),請避免直接把 hashed password 寫在裡面。後續我們會介紹 sops-nix 等 secrets management 方案。

如果你用了 zsh 作為 shell

別忘了同時啟用 zsh,否則系統會找不到這個 shell:

programs.zsh.enable = true;

開啟 SSH 服務(services.openssh

SSH 是遠端管理 server 的基本功——尤其當你像我們一樣從 MacBook SSH 進 NixOS server 時,這個服務至關重要。在 NixOS 上,開啟 SSH 只需要一行:

services.openssh.enable = true;

就這樣?對,就這樣。NixOS 的 declarative 配置就是這麼簡潔。

不過,為了安全性,建議你加上更多設定:

services.openssh = {
  enable = true;
  settings = {
    # 禁止 root 遠端登入
    PermitRootLogin = "no";
    # 禁止密碼登入,僅允許 SSH key
    PasswordAuthentication = false;
  };
};

搭配防火牆設定

NixOS 預設會開啟 firewall,所以你需要確認 SSH 的 port 有打開:

networking.firewall.allowedTCPPorts = [ 22 ];

不過好消息是,當你啟用 services.openssh.enable = true 時,NixOS 會自動在 firewall 中開啟 port 22,通常不需要手動設定。

設定 SSH Key 認證

建議搭配 SSH key 來登入,更安全也更方便:

users.users.james = {
  isNormalUser = true;
  description = "James Hsueh";
  extraGroups = [ "wheel" "networkmanager" ];
  openssh.authorizedKeys.keys = [
    "ssh-ed25519 AAAAC3Nza... james@my-laptop"
  ];
};

把你的 public key 貼上去,之後就能用 SSH key 直接登入,不需要輸入密碼。

💡 MacBook 使用者提示:你的 public key 通常在本地 MacBook 的 ~/.ssh/id_ed25519.pub(或 id_rsa.pub)。可以在本地終端機用 cat ~/.ssh/id_ed25519.pub 查看,然後把內容貼到上面的 authorizedKeys.keys 裡。如果還沒有產生過 SSH key,先在本地執行 ssh-keygen -t ed25519


套用變更與驗證

所有修改都寫好之後,在 NixOS server 上用一個指令讓變更生效:

# 在 NixOS server 的 SSH session 中執行
sudo nixos-rebuild switch

這個指令會:

  1. 評估(evaluate)整份 configuration.nix
  2. 建置(build)所有需要的套件與設定
  3. 切換(switch)到新的 system generation
  4. 啟動相關 service(如 sshd

驗證結果

在 NixOS server 上逐一驗證:

# (在 NixOS server 上)確認套件已安裝
which git
git --version

# (在 NixOS server 上)確認使用者已建立
id james

# (在 NixOS server 上)確認 SSH 服務正在執行
systemctl status sshd

接著,回到你的 MacBook 終端機,測試 SSH 連線:

# (在本地 MacBook 上)嘗試用 SSH key 連線
ssh james@<your-nixos-server-ip>

如果能成功登入,恭喜你,SSH 配置完成!

如果出錯了怎麼辦?

不用緊張!NixOS 最強大的特性之一就是可回滾。如果新的配置有問題:

# (在 NixOS server 上)回滾到上一個 generation
sudo nixos-rebuild switch --rollback

甚至在開機時,GRUB 選單也會列出所有歷史 generation,你可以選擇舊的配置開機。這就是 NixOS immutable 設計帶來的安全感。

⚠️ SSH 使用者注意:如果你在修改 SSH 設定時不慎搞壞了連線(例如改了 port 或 key 設定),可能會導致無法遠端登入。建議在修改 SSH 相關配置時,保持至少一個 SSH session 不要斷線,先在另一個終端機視窗測試新配置是否能正常連入。


完整配置範例

把今天學到的內容整合在一起,你的 configuration.nix 大概會長這樣:

# /etc/nixos/configuration.nix
{ config, pkgs, ... }:

{
  imports =
    [ ./hardware-configuration.nix ];

  # Bootloader
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  # 網路
  networking.hostName = "my-nixos";
  networking.networkmanager.enable = true;

  # 時區與語系
  time.timeZone = "Asia/Taipei";
  i18n.defaultLocale = "en_US.UTF-8";

  # 系統套件
  environment.systemPackages = with pkgs; [
    vim
    wget
    curl
    git
    htop
    tmux
    unzip
  ];

  # 使用者
  users.users.james = {
    isNormalUser = true;
    description = "James Hsueh";
    extraGroups = [ "wheel" "networkmanager" ];
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 AAAAC3Nza... james@my-laptop"
    ];
  };

  # SSH
  services.openssh = {
    enable = true;
    settings = {
      PermitRootLogin = "no";
      PasswordAuthentication = false;
    };
  };

  # 防火牆
  networking.firewall.enable = true;

  system.stateVersion = "24.05";
}

小結

今天我們學會了 NixOS 最核心的三項基礎配置:

學到了什麼對應設定
安裝系統套件environment.systemPackages
管理使用者users.users.<name>
開啟 SSH 服務services.openssh.enable

更重要的是,你開始體會到 NixOS 的哲學:所有系統狀態都由 configuration.nix 定義。這個檔案就像是你整台機器的 blueprint,任何時候、任何地方,只要有這個檔案,就能重建出一模一樣的系統。

這就是 declarative configuration 的威力。


明日預告

Day 3:Nix 語言入門

configuration.nix 裡那些 with{ ... }[ ... ] 到底是什麼?明天我們會正式認識 Nix 語言的基礎語法——變數、型別、function、let ... in,讓你讀得懂、寫得出更複雜的配置。

我們明天見! 🚀