blog.anqou.net
rss
author
tags

NixOS を使い始める

NixOS を使い始めたときに設定をしたときのメモ。前半は VM に入れた NixOS で作業している。後半からは実機にインストールして作業する。自分用のメモを仕立て直したものなので読みにくいかも。

NixOS の使用感を知りたい人は一番下までスクロールすると書いてある。

#参考にするもの

公式のドキュメントに良いチュートリアルを見つけられなかったので、こちらの日本語記事を参考にする:https://zenn.dev/asa1984/articles/nixos-is-the-best

#ISO イメージをダウンロードする

公式サイトから GNOME の ISO イメージをダウンロードする:https://nixos.org/download/

#vim と gnome-terminal を入れる

GNOME で立ち上げると XTerm は入っているが gnome-terminal は入っていない。Vim も入っていないので入れる。NixOS の設定は /etc/nixos/configuration.nix にあるので、これを書き換える。

environment.systemPackages = with pkgs; [
    vim
    pkgs.gnome.gnome-terminal
]

みたいにする。その後

sudo nixos-rebuild switch

すると入る。

#Nix command と flakes を有効化する

nix というコマンドがあって、nix-HOGEHOGE というコマンドを統一的なインターフェースで扱えるようになっているらしい。現時点では実験的な機能でデフォルトでは入っていないらしいので、これを入れる:https://nixos.wiki/wiki/Nix_command

あと Flake とかいう、パッケージをいい感じに使えるようになる機能も実験的な機能ということになっているので、これも入れる:https://nixos.wiki/wiki/Flakes

日本語記事では以下のようにしていれている:

nix = {
    settings = {
        experimental-features = ["nix-command" "flakes"];
    }
}

が、以下のようにしてもよさそう:

nix.settings.experimental-features = ["nix-command" "flakes"];

#Flake を作る

自分の環境の設定は Flake とかいうのを作って管理するらしい。~/.dotfiles に Git repo を作り、/etc/nixos 配下のファイルを全部コピーしてくる。追加で flake.nix も作る。

flake.nix の書き方はここに説明がある:https://nixos.wiki/wiki/Flakes#Flake_schema

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
  };

  outputs = inputs: {
    nixosConfigurations = {
      myNixOS = inputs.nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          ./configuration.nix
        ];
      };
    };
  };
}

inputs が attribute set で、outputs はこれ(に拡張が入ったもの)を受け取って attribute set を返す関数。どういう attribute set を返せばよいかは schema に書いてある。ここでは nixosConfigurations を返す。これは nixos-rebuild switch --flake .#<hostname> したときに使われる。 outputs 中では inputs が引数として渡されているので、これを参照できる。 nixpkgs.lib.nixosSystem には NixOS のシステムを立ち上げるために必要なパッケージが入っているらしい。https://www.reddit.com/r/NixOS/comments/13oat7j/comment/jl6aka8/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button

#configuration.nix を書き換える

ドキュメント:

##users.*

ユーザの設定。https://nixos.org/manual/nixos/stable/#sec-user-management

mutableUsers = false にしたい。するとパスワードを configuration.nix で設定する必要がある。mkpasswd コマンドに打ち込んで得た結果を users.users.anqou.hashedPassword に突っ込む。

##programs.*

Appendix A のドキュメントを見ながら必要そうなものを入れるのがよさそう。とりあえずは日本語記事に書いてあったものを入れる。

##IME の設定

https://nixos.org/manual/nixos/unstable/#module-services-input-methods

stable と unstable で設定方法が異なる。たぶん unstable を使っているので以下のように書く:

  i18n.inputMethod = {
    enable = true;
    type = "fcitx5";
    fcitx5.addons = with pkgs; [ fcitx5-mozc ];
  };

Nix の with pkgs; [ fcitx5-mozc ][ pkgs.fcitx5-mozc ] と等価らしい。https://nix.dev/tutorials/nix-language.html#with

##JP キーボードの設定

IME の設定を有効にするために再起動したところ、キーボード設定が us になっている。configuration.nix には services.xserver.xkb.layout = "jp" と書いてあるのに。

というか services.xserver.enable = true なのに Wayland が立ち上がっている。なんてこったい。

https://discourse.nixos.org/t/enabling-x11-still-results-in-wayland/25362/2 によると ↑ は X を使えるようにするだけで、実際にどちらを使うかは GDM の歯車次第らしい。

Hyprland を使う都合上 Wayland で立ち上がってほしいのは事実なので、wayland の設定をする。

と思ったのだが、Wayland だと統一的な設定方法が用意されていなくて、それぞれの WM で設定する必要がありそう。GNOME は単に GUI の設定アプリから設定しろという話らしい。

と思ったのだが、設定アプリから設定したものは再起動すると初期化されてしまうっぽい。こういうのは dconf で設定する必要がありそう。home-manager とかいうやつを使ってもできるし、単に programs.dconf でも設定できそう。https://wiki.nixos.org/wiki/GNOME#dconf_settings

まず dconf watch / を実行してから GNOME の設定画面をいじると、以下のような表示が出る:

/org/gnome/desktop/input-sources/sources
  [('xkb', 'jp')]

のでこれをもとに configuration.nix をいじる。

dconf の式を Nix の式として書く必要がある。https://nixos.org/manual/nixpkgs/stable/#sec-functions-library-gvariant が公式のドキュメント。https://github.com/nix-community/dconf2nix なども使えそう。今回は https://discourse.nixos.org/t/dconf-org-gnome-desktop-input-sources-sources-gets-reverted-upon-login/39263 を参考にした。

    dconf = {
      enable = true;
      profiles.user.databases = [
        {
          lockAll = true;
          settings = {
            "org/gnome/desktop/input-sources" = {
              sources = [(lib.gvariant.mkTuple ["xkb" "jp"])];
            };
          };
        }
      ];
    };

##フォントの設定

日本語記事の通りにする。fonts.fontDir.enable = true; は Flatpak が正しく動くために必要らしい:https://nixos.wiki/wiki/Fonts

##ZSH のコマンド履歴が再起動で消えないようにする

ZSH の設定をする。shellInit を使えば好きな .zshrc を作れるので、ここに bindkey '^R' history-incremental-search-backward と書いておく。

##NVIDIA driver などのハードウェアの設定

https://nixos.wiki/wiki/Nvidia とかを見ながら設定するのがよいが、実は https://github.com/NixOS/nixos-hardware を使えば必要な設定を勝手にやってくれる説がある。導入だけして、必要なものを後から入れることにするのがよさそう。

##/nix/store を最適化する・GC を有効化する

設定は普通にできる。手動で GC を動かす場合は nix-store --gc を打つ。

##Git repo が dirty でもビルドさせる

Git repo を作った状態で commit せずに nixos-rebuild switch しようとすると error: path '...' does not exist とか言われて死んでしまう。

git add . && git commit -m wip したら大丈夫だった。

あるいは sudo nixos-rebuild switch --flake path:.#anise すればよかった。

##Rootless Docker を入れる

virtualisation.docker.* をいい感じに設定する:https://wiki.nixos.org/wiki/Docker

#home-manager を使う

user environment を扱うためのシステムらしい。

ドキュメント:

manual に書いてあるインストール方法と日本語解説記事のインストール方法が派手に違う(homeConfigurations が無い)が、とりあえず manual 側にそろえる。

user の権限で nixpkg をインストールできて便利という話っぽいが、真に便利なのはたぶん programs.* で、rofi などがインストールできる。あと programs.zsh.* とかもいろいろある。微妙に configuration.nix とは名前が違うのでだるい。

##configuration.nix との重複

configuration.nix と home-manager の双方で設定できる項目がいくつかあり、お互いに排他だったり相補的だったり、どっちかが動かなかったりするのでややこしい。例えば:

#Nix の Wiki

なんか知らんけど二つある:

歴史的経緯らしい:https://nixos.wiki/wiki/NixOS_Wiki:History

#ホームディレクトリ配下のフォルダ名を英語にする

いつもの

LANG=C xdg-user-dirs-gtk-update

#Tilix の設定を宣言的に管理する

以下のようにするとショートカットを設定できる。

"com/gexperts/Tilix/keybindings" = {
  app-new-session = "F2";
  session-switch-to-terminal-down = "<Shift>Down";
  session-switch-to-terminal-left = "<Shift>Left";
  session-switch-to-terminal-right = "<Shift>Right";
  session-switch-to-terminal-up = "<Shift>Up";
  win-switch-to-previous-session = "F3";
  win-switch-to-next-session = "F4";
  session-add-down = "<Shift>F2";
  session-add-right = "<Primary>F2";
  terminal-copy = "<Primary><Alt>c";
  terminal-paste = "<Primary><Alt>v";
};

#Thunderbird のプロファイルを宣言的に設定しない

home-manager を使うと thunderbird のプロファイルを宣言的に設定できる:

programs = {
  thunderbird = {
    enable = true;
    profiles = {
      main = {
        isDefault = true;
      };
    };
  };
};

accounts.email.accounts = {
  "[email protected]" = {
    primary = true;
    realName = "Ushitora Anqou";
    thunderbird.enable = true;
    address = "[email protected]";
    userName = "[email protected]";
    flavor = "gmail.com";
  };
};

が、結局 Thunderbird を起動すると GMail のパスワード設定を求められるので不便。結局データは ~/.thunderbird に入るのでこれをコピー&ペーストすればいい。ということで上のやつは使わない。home-manager で programs.thunderbird.enable = true すると programs.thunderbird.profiles も設定しないと怒られるので、configuration.nix で programs.thunderbird.enable = true する。

#homeConfigurations がなくてもいいのか

homeConfigurations を使って設定する解説記事ばかりの中、マニュアルには書いてなかったので使っていなかったが、今のところ普通に動いている。どうも standalone setup で home-manager switch するときに使う設定項目っぽい。

https://apribase.net/2024/07/14/home-manager-module/ とかが参考になりそう?

#Cica

nixpkgs に Cica はないが、Ricty の nixpkg の記述を参考に以下のようにすればインストールできた。意外と Nixpkg は簡単に作れる。

fonts = {
  packages = with pkgs; [
    # ...

    # Cica
    # cf. https://github.com/NixOS/nixpkgs/blob/nixos-24.05/pkgs/data/fonts/ricty/default.nix
    (stdenv.mkDerivation rec {
      pname = "cica";
      version = "5.0.3";
      src = fetchurl {
        url = "https://github.com/miiton/Cica/releases/download/v${version}/Cica_v${version}.zip";
        sha256 = "cbd1bcf1f3fd1ddbffe444369c76e42529add8538b25aeb75ab682d398b0506f";
      };
      nativeBuildInputs = [ unzip ];
      unpackPhase = "unzip $src";
      installPhase = "install -m644 --target $out/share/fonts/truetype/cica -D Cica-*.ttf";
    })
  ];

#実機に NixOS をいれる

##GRUB で正しく起動する

入れるのはすぐだったが、その後 GRUB で起動させるまでが大変だった。どうやら boot に失敗していたようで、なにを apply しても再起動すると巻き戻ってしまう状態だった。以下のように設定してうまく行った。まず configuration.nix

  # Bootloader.
  boot.loader = {
    grub = {
      enable = true;
      device = "nodev";
      useOSProber = true;
      efiSupport = true;
    };
    efi = {
      canTouchEfiVariables = true;
      efiSysMountPoint = "/boot/efi";
    };
  };

続いて hardware-configuration.nix

  fileSystems."/boot/efi" =
    { device = "...";
      fsType = "vfat";
      options = [ "fmask=0077" "dmask=0077" ];
    };

以上の設定は https://nixos.wiki/wiki/Bootloader#Keeping_kernels/initrd_on_the_main_partition に書いてあった。正直この説明を読んでも、これを適用すべきなのかどうかはさっぱりわからなかったが、やったら動いた。

##/omion にマウントして必要なファイルを ~/ に配置する

システムディスクとは異なる btrfs のディスクを /omion というパスにマウントする。まず hardoware-configuration.nix を書き換えて /omion にディスクをマウントする。

  fileSystems."/omion" =
    { device = "/dev/disk/by-uuid/...";
      fsType = "btrfs";
      options = [ "subvol=omion" ];
    };

続いて /omion 配下のディレクトリをホームディレクトリ配下へシンボリックリンクを張る。 普通に絶対パスを書くとエラーになるので mkOutOfStoreSymlink を使う:https://github.com/nix-community/home-manager/pull/1211

    file = {
      ".hoge" = {
        target = ".hoge";
        source = config.lib.file.mkOutOfStoreSymlink /omion/hoge;
      };
    };

##クリップボードを有効化する

wl-clipboard を入れる。

##formatter を有効化する

https://nix.dev/manual/nix/2.17/command-ref/new-cli/nix3-fmt を見ながら以下を設定した:

# flake.nix
{
  outputs = { nixpkgs, self }: {
    formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.alejandra;
  };
}

nix fmt でフォーマットできる。

##GDM の auto suspend を無効化する

デフォルト設定では GDM の auto suspend が有効化されているため、WoL で起動して SSH で接続していると、いきなり SSH が切れる(1 敗)。

無効化する:

services.xserver.displayManager.gdm = {
  enable = true;
  autoSuspend = false;
};

#現在動いているもの

現在使われているファイル群は /usr/share とかを探しに行っても存在しないが、以下にある:/run/current-system/sw/

home-manager で入れたものは以下にある:/etc/profiles/per-user/anqou/

実態はシンボリックリンクになっている。

#書き捨てのシェルスクリプト

/usr/bin/bash とかが無いので shebang が普通には書けない。https://zenn.dev/natsukium/scraps/d260e091cb8fdc とかを参考に、以下のように書くと動く:

#!/usr/bin/env nix-shell
#! nix-shell -i bash --pure
#! nix-shell -p bash
## その他に必要なものがあったら↑に書く。

# ここに Bash スクリプト

#ローカルでカスタムのパッケージをビルド

unstable にもまだ入っていない Hyprland の最新版を使いたかったので、手元でビルドする。まず nixpkgs からソースを探す。https://search.nixos.org/packages から探して “Source” からリンクを飛ぶと見つかる。Hyprland の場合は https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/hy/hyprland/package.nix にある。これをローカルにコピーする。

続いて version の値を最新版に合わせ、fetchFromGitHub の中身を修正する。再現性を担保するために SHA256 ハッシュを計算する必要があるが、これには nix-prefetch-git コマンドが使える。以下のように使う:

nix-prefetch-git --rev v0.46.2 https://github.com/hyprwm/Hyprland

続いてこの package.nixconfiguration.nix から使うように設定する。これには pkgs.callPackage を使う。Hyprland の場合 stdenv をいい感じに設定する必要があることが nixpkgs の all-packages.nix を見るとわかるので、これを考慮して以下のようにする:

    hyprland = {
      # ...
      package = pkgs.callPackage ./hyprland/package.nix {
        stdenv = gcc14Stdenv;
      };
      # ...
    };

1 ヶ月半くらい NixOS を使った感想

configuration.nix 経由で様々なソフトウェアを宣言的に管理できるのがかなり体験として良い。普通の(Ubuntu や Arch Linux などの)distro だと apt とか pacman とかを使ってソフトウェアをインストールし、Wiki を見ながら /etc/ 配下の設定ファイルをいい感じにいじって、とかする必要があるところ、NixOS だと configuration.nixhoge.enable = true みたいにすればインストールや設定ファイルの配置が行われ、設定を変更する際も hoge.settings.foo = "bar" みたいに予め用意された「つまみ」を configuration.nix から変更すれば済む。どういう設定のツマミがあるかも https://search.nixos.org/optionshttps://home-manager-options.extranix.com を見れば一覧で表示されるため分かりやすい。インターネット上の NixOS の情報量は Arch Wiki の情報量の多さと比べると少ないが、このオプションの一覧表示のおかげであまり気にならない。

一方で ad hoc かつ一時的にシステムの設定ファイルを書き換えることは残念ながらやりにくい。実際に遭遇した例でいうと、自動的に Minikube を起動して minikube ip を叩いて出てきた IP アドレスを自動的に /etc/hosts に設定するスクリプトは /etc/hosts が NixOS によって read only に設定されてしまったため動かなくなった。仕方がないので IP アドレスを設定するところだけマニュアルで configuration.nix を書き換えるフローに変更した。また Hyprland や Neovim の設定ファイルなども Nix の式として組み込むことができるようになっているが、これをやると Hyprland・Neovim の設定を挙動を見ながらちょっとずつ書き換えていこうにも、書き換えるたびに nixos-rebuild を打つ必要があり面倒である。仕方ないのでこれらの設定ファイルを Nix に寄せるのは諦めた。

その他、シェルスクリプトがそのまま動かなかったり、aqua や opam といった他のパッケージマネージャと相性が悪かったりと細かい不具合は色々あるが、都度 NixOS 向けに書き換えていけばいいのであまり大きな問題にはなっていない。特に OCaml に関しては opam2nix という素晴らしいツールがあるので、これを使って脱 opam を始めている。最近自分が管理している OCaml のコードに flake.nix ファイルが commit されつつあるのはそういう理由である。

Nix の文法や意味論は、慣れるまで少し大変(特に list と attribute set のセパレータの区別とか)だが、そこまで難しかったり奇妙だったりするようには見えない。ただしこれは自分が OCaml などの関数型プログラミング言語のパラダイムに慣れているからかもしれない。

nixpkgs は主要な distro の中で最多のパッケージを誇ると様々なところで喧伝されているように、必要なソフトウェアやその他のものはおおよそ揃うように思える。揃わない場合でも、 Nix を使って手元でソフトウェアをビルドすることは容易にできる。 Arch Linux を使っていた頃は PKGBUILD ファイルを一度も手で書いたことはなかったのだが、 NixOS では Nix を使わないとソフトウェアのビルドが面倒そうなので、自然と Nix のファイルを書いて手元でビルドするようになった。一般的な Autotools や CMake を使うビルドのほか、cargo や Go のビルドを簡単に行うためのフレームワークが Nix 側から提供されているので、見た目ほど難しくはなさそう。ただし nixpkgs に収容されているパッケージの中にはどのようにビルドされているのかが Nix のファイルを読んでもわからないものが多数あるので、このあたりはまだ修練が必要そう。

という感じで、色々細かい問題はあるものの、概ね問題なく NixOS を使えている。しばらくはこの環境をメインで使っていくつもり。