nix home-manager で dotfiles を管理する


はじまり

Linux を使うシーンって結構あるし、ユーザー環境を (dotfiles) を stow とか chezmoi とかでいい感じに共有したいな、としばらく試しながら、stow も chezmoi も正直スッキリしない・・・と感じていた。

そこそこ作業 (Linux Ricing) しながらも、スッキリピッタリな解決策がないものかと思っていたら、たまたま YouTube で github:nix-community/home-manager を紹介している動画と出会った。

実はもともと、NixOS というユーザーの環境からシステムワイドの設定まですべてを記述してしまおうという Distro がある、と噂を聞いていた。
それを聞いたのは結構古い記憶だったから、あまり気にしていなかったのだけれど、まさに今、解決したい問題は NixOS のコンセプト 1 で解決できることに気が付いた。

Home-manager を試そうと思った理由

Manage a user environment using Nix - github:nix-community/home-manager

Q. ではあなたはなぜ NixOS ではなくて home-manager を試そうと思ったの?

  1. 私がアクセスできる Linux を全て NixOS にするのは(私にとって)規模が大きいので、まずは手元のユーザー環境を Nix で記述することで、軽く学んでいきたかった。
  2. home-manager は、NixOS の上でも使えるらしく、home-manager 管轄のコンフィグは dotfiles としての役割を残したまま移行できそうだったから。(すべてを NixOS の設定に寄せる必要はないし、home-manager の管理なら他の UNIX 系システムで使えるように見える)

やっていく

インストールなどは公式ドキュメントに則って行う。
Arch は pacman でも Nix を入れられるのだが、私は公式のスクリプトを使って入れた。
nixpkgs は stable の 24.11 を使うことにする。深いワケは今のところない。

基本的には やりたいこと→参考資料→適用→トラブルシューティング の順で書いていこうと思う、あなたにとって気になる見出し・参考になる部分があれば嬉しい。

Nix Command と Nix Flakes を使う

Nix command - NixOS Wiki
Flakes - NixOS Wiki

私が暇なときにみていた動画では、だいたいサブコマンドや flake.nix を使っていたのだが、そのサブコマンドを使うのは nix command というらしい。flake.nix は Nix flakes の機能で使うファイルらしい。
これらは experimental な機能らしいが、これから nix command や Nix flakes の時代になる予感がするので、使っていきたい。

有効化するには、

  1. Enable flakes temporarily
  2. Enable flakes permanently in NixOS
  3. Other Distros, with Home-Manager
  4. Other Distros, without Home-Manager

とあったので、1と3を活用する

Home Manager で Nix Command と Nix Flakes を使う

sec-flakes-prerequisites | home-manager index.xhtml
nix.settings | Home Manager - Option Search
nix.package | Home Manager - Option Search

Other Distros, with Home-Manager で紹介されているが、少しだけ記述を変えなければいけないので一例を載せておく

in home.nix

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

home-manager/modules/misc/nix.nix at 2f23fa308a7c067e52dfcc30a0758f47043ec176 · nix-community/home-manager · GitHub
どうやら nix.settingsnix.extraOptions が空ではないとき、nix.package が必要らしいので入れてあげる。

.nixdefexpr がホーム直下にあるのが気になる

[[xdg-ninja]] によると、

[nix]: /home/tenzyu/.nix-defexpr New nix command line interface supports XDG Base Directory but Old Commands will still create these directories.
To use the XDG spec with the old command line, add to /etc/nix/nix.conf :
use-xdg-base-directories = true
You also have to manually move the the file to XDG_STATE_HOME:
mv "$HOME/.nix-defexpr" "$XDG_STATE_HOME/nix/defexpr"
See the Manual: https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-use-xdg-base-directories https://nixos.org/manual/nix/stable/command-ref/conf-file#conf-use-xdg-base-directories

ということなので、やってやる。

モジュール化したい

Modularize Your NixOS Configuration | NixOS & Flakes Book

home-manager を選んだほとんどの理由はここにあるのだが、私はコンフィグをモジュール化したい。具体的にやりたいことは、プログラム単位、ユーザー単位で記述して、必要なものだけ取り出すのを簡単にしたい。

├── flake.nix
└── user
    ├── profiles
    │   ├── common.nix
    │   ├── default.nix
    │   └── tmpl-default.nix
    └── programs
        ├── btop
        │   └── default.nix
        └── zsh
            ├── config/
            └── default.nix

home-manager はユーザー環境を記述できる。
今後 NixOS と連携することを考えて、ディレクトリを、home-manager 管轄のユーザー領域のコードとして user と、NixOS 管轄のシステム領域のコードとして system で切って分ける計画にした。

やっていく2

ここからは作業、トラブルシューティングを書いていく。
まずは cli か gui か分類して、cli のプログラムを積極的に移動していく。

Tokyo Night テーマを入れたい

programs.bat.themes | Home Manager - Option Search
Example では pkgs.fetchFromGitHub をつかっていたので、真似をする。

Nixpkgs Reference Manual
こういうのは fetcher と呼ばれているらしく、再現性を損なわずに外部のリソースを使う方法を考えた先人たちが作り出したものらしい。

nixpkgs/pkgs/build-support/fetchgithub/default.nix at master · NixOS/nixpkgs · GitHub
fetchFromGitHub はなんやかんやして fetchgit や fetchzip を呼び出してくれるラッパーっぽい。

nix-prefetch-url - Nix Reference Manual
--unpack フラグを渡して、tarball の URL を与えると、fetchFromGitHub で使える hash を返してくれるらしい。

ここまで全部やるのは結構めんどくさいけど、冪等性のためにはそういうものかって感じではある。
nix-prefetch-url --unpack https://github.com/folke/tokyonight.nvim/archive/refs/tags/v4.10.0.tar.gz としてハッシュを得た。

 cat user/programs/bat/default.nix 

{ pkgs, ...}:
{
  programs.bat = {
    enable = true;
    themes = {
      tokyo-night = {
        src = pkgs.fetchFromGitHub {
          owner = "folke";
          repo = "tokyonight.nvim";
          rev = "v4.10.0";
          sha256 = "02662k6kxaf19w17fq71zc6hv4yylgzzmrrhhzid0sz0ghafb9dw";
        };
        # bat はsublime 構文を使っているらしい
        file = "extras/sublime/tokyonight_night.tmTheme";
      };
    };
    config = {
      theme = "tokyo-night";
    };
  };
}

Catppuccin テーマを入れたい

これまでなんとなく TokyoNight を使っていたが、気分転換も兼ねて今日から Catppuccin を使いたくなったので、やっていく。

Ports • Catppuccin
たまたま Catppuccin のホームページにこんなものがあることを知ったので、眺めていると、
GitHub - catppuccin/nix: ❄️ Soothing pastel theme for Nix
たまたま nix といい感じに仲良くしてくれるものを見つけたので、使っていく。

直感的にはプログラムごとにテーマを記述したほうが良い気がするが、どうせ全部やるのと、乗り換えやすさを考慮して github:catppuccin/nix を使って、グローバルで適用した。

Man が Locale をセットできない

❯ man
/home/tenzyu/.local/state/nix/profile/bin/man: can't set the locale; make sure $LC_* and $LANG are correct

私は明示的に nix で man を入れているわけではないので、いつから nix 下の man を使うようになったのか正直わからないが、このままでは man が困ってしまうので直していく。

Locales - NixOS Wiki
丁寧に Wiki に書かれていたので、記事内の nix shell を home.sessionVariables と見立てて記述する
home.sessionVariables | Home Manager - Option Search

  home.sessionVariables = {
    # https://nixos.wiki/wiki/Locales
    LOCALE_ARCHIVE = "${pkgs.glibcLocales}/lib/locale/locale-archive";
  };

環境変数で XDG に準拠したい

home-manager/modules/misc/xdg.nix at release-24.05 · nix-community/home-manager · GitHub
あまり良くわからないけど、ハードコーディングしなくても、config.xdg.cacheHome とかでアクセスできそう。
xdg.enable = true; にしなくても使えそうだけど、こうすると home.sessionVariablesXDG_CACHE_HOME とかを入れてくれるらしいよ(便利!)

ちなみに config.xdg.enable とかでアクセスされてるパッケージもあるらしい。
config.xdg.enable | Code search results · GitHub

home-manager/modules/home-environment.nix at 2f23fa308a7c067e52dfcc30a0758f47043ec176 · nix-community/home-manager · GitHub
その後たまたま home.preferXdgDirectories を見つけたので、真にしておく。

そんなにアクセスされていないように見えるが・・・
home.preferXdgDirectories | Code search results · GitHub

XDG_RUNTIME_DIR は副作用の要因になるみたいで、簡単には使わせてもらえないらしい。

    NPM_CONFIG_TMP="$XDG_RUNTIME_DIR/npm";

例えば上記のような変数の指定に使いたいのだけれど、今回は "${config.xdg.stateHome}/npm-runtime"; とかでお茶を濁そうと思う。

スマートな解決方法を知っている人はぜひ @tenzyudotcom に DM してほしい。

home.sessionVariables を読みにいく先を変えたい

私はホーム直下にドットファイルがあるのが好きじゃないので、~/.nix-profile ではなくて ~/.local/state/nix/profiles/profile を使っている。
~/.nix-profile を消しているので、zsh が見つけられずに困っているので直していく。

home-manager/modules/programs/zsh.nix at a9953635d7f34e7358d5189751110f87e3ac17da · nix-community/home-manager · GitHub
zsh は

. "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh"

とすることで、home.sessionVariables の変数を適用していることがわかった。

home-manager/modules/home-environment.nix at 2f23fa308a7c067e52dfcc30a0758f47043ec176 · nix-community/home-manager · GitHub
私はこれまで home.profileDirectory を知らなかったのだけれど、特定の条件では勝手にやってくれるらしい。

home-manager/modules/home-environment.nix at 2f23fa308a7c067e52dfcc30a0758f47043ec176 · nix-community/home-manager · GitHub
最初は上書きすればいいと思っていたのだけれど、Read-only らしいので、"${config.xdg.stateHome}/nix/profile" を使ってくれる設定を再現する。

  nix = {
    package = pkgs.nixFlakes;
    settings = {
      experimental-features = [ "nix-command" "flakes" ];
      use-xdg-base-directories = true;
    };
  };

とりあえずこれで望んでいる場所を参照してくれた。

ちなみに、 warning: ignoring the client-specified setting 'use-xdg-base-directories', because it is a restricted setting and you are not a trusted user と毎回いわれると悲しいので、nix.settings.extra-trusted-users に自分のユーザー名を追加した。

起動しないアプリを救いたい

GPU を使うプログラムが起動しないことがある。
それは、NixOS 環境下でないと、グラフィックドライバを見つけられないから らしい。
その解決策として NixGL を使うのがデファクトスタンダードらしい。
GitHub - nix-community/nixGL: A wrapper tool for nix OpenGL application [maintainer=@guibou]

home-manager や nixgl の issue を見て回ると、どうやら最近 (24.11) からは、便利な関数が用意されていて、次のようにすることでアプリケーションをラップすることができる。

# flake.nix
{
  inputs = {
    nixgl.url = "github:nix-community/nixGL";
  };
}
{inputs, config, pkgs, ...}: {
  # nixGL.wrap をするための準備
  nixGL.packages = inputs.nixgl.packages;
  nixGL.vulkan.enable = true;
  nixGL.defaultWrapper = "mesa";
  nixGL.installScripts = [
    "mesa"
  ];

  programs.kitty = {
    enable = true;
    package = config.lib.nixGL.wrap pkgs.kitty;
  }
}

config.lib.nixGL.wrap pkgs.kitty; の部分でラップされていて、kitty でラップ済みのプログラムとして実行できる(すごい!)

終わりに

個人的に Nix に満足していて、手元のノートパソコンは既に NixOS に乗り換えた。

Obsidian を使い始めたときにも同じような感想を持ったのだけれど、これまで雲散霧消してきたものが、今後は再利用可能だと思うと、とても嬉しいし、やってよかった。
宣言的な分 ブラックボックスであったり、Nix の思想との相性だったりあるかもしれないけど、もし暇なら試してみてほしい。

たまたま噂に聞いていた Nix のおかげで良い経験ができたので、今後もアンテナを張っていきたいと思う。
例としては、近いうちに Devbox なんかも試そうと思う。

Footnotes

Footnotes

  1. Reproducible, Declarative and Reliable - Nix & NixOS | Declarative builds and deployments