NixのHome ManagerでTailscaleをインストールする(systemdとlaunchdの設定)
はじめに
先日MacBookにNixのHome Managerを導入したのですが、その時にHomebrewを削除した快感が忘れられず、VPSのUbuntuにも導入してしまいました。
いつ契約したかもわからないVPSでしたが、 home.nix
をそのまま持っていくだけでMacBookと同じ環境を再現できて感動です。 sudo apt remove
しまくりたいと思います。
Tailscaleやmoshで外部から接続したい
さて、VPSなので当然外部から簡単に接続する方法を考えたいです。有名なのはプライベートネットワークを構築するための Tailscale や不安定な通信環境でSSHっぽいことができる mosh 辺りでしょうか。
Home Managerでは基本的に
home.packages = with pkgs; [
mosh
tailscale
];
これだけでパッケージのインストールができるのですが、デーモン化するためにsystemd等の設定が必要な場合があります。
実際にmoshは勝手に動きましたが、tailscaleはそのままでは動きません。また、moshの代わりにインストールを試みたEternal Terminalもそのままでは動きませんでした。
systemdとlaunchdを設定する
systemdとlaunchdは home.nix
内で設定することができます。launchdはmacOSの「ログイン項目」になるものです。
以下はTailscaleとEternal Terminalの例です。
Tailscale
{ config, pkgs, ... }:
let
homeDirectory = /home/nixuser
in {
# 省略
# Tailscaleをインストール
home.packages = [ pkgs.tailscale ];
# Linux(Ubuntu)の場合はsystemdを設定
systemd.user.services.tailscaled = if pkgs.stdenv.isDarwin then
null
else
{
Unit = {
Description = "Tailscale Daemon";
After = [ "network.target" ];
};
Service = {
# 制限されたモードでtailscaledを立ち上げる
# https://tailscale.com/kb/1112/userspace-networking?q=userspace
# `${homeDirectory}/.nix-profile/bin/tailscaled` でも良いはず
ExecStart = "${pkgs.tailscale}/bin/tailscaled --tun=userspace-networking --state=${homeDirectory}/.tailscale.state";
Restart = "always";
};
Install = {
WantedBy = [ "default.target" ];
};
};
# macOSの場合はlaunchdを設定
launchd.agents.tailscaled = if pkgs.stdenv.isDarwin then
{
enable = true;
config = {
Label = "com.nixuser.tailscaled";
# 制限されたモードでtailscaledを立ち上げる
ProgramArguments = [
"${pkgs.tailscale}/bin/tailscaled"
"--tun=userspace-networking"
"--state=${$homeDirectory}/.tailscale.state"
];
RunAtLoad = true;
KeepAlive = true;
};
};
else
null;
それぞれ有効化します。
# systemdをユーザー権限で設定
systemctl --user enable --now tailscaled
# launchdをユーザー権限で設定
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.nixuser.tailscaled.plist
# ログイン
tailscale up
Eternal Terminal
{ config, pkgs, ... }:
let
homeDirectory = /home/nixuser
in {
# 省略
# Eternal Terminalをインストール
home.packages = [ pkgs.eternal-terminal ];
# Linux(Ubuntu)の場合はsystemdを設定
systemd.user.services.tailscaled = if pkgs.stdenv.isDarwin then
null
else
{
Unit = {
Description = "Tailscale Daemon";
After = [ "network.target" ];
};
Service = {
ExecStart = "${pkgs.eternal-terminal}/bin/etserver";
Restart = "always";
};
Install = {
WantedBy = [ "default.target" ];
};
};
# macOSの場合はlaunchdを設定
launchd.agents.tailscaled = if pkgs.stdenv.isDarwin then
{
enable = true;
config = {
Label = "com.nixuser.etserver";
ProgramArguments = [ "${pkgs.eternal-terminal}/bin/etserver" ];
RunAtLoad = true;
KeepAlive = true;
};
};
else
null;
systemctl --user enable --now tailscaled
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.nixuser.etserver.plist
Eternal Terminalの接続先サーバーの場合は、以下のようにシンボリックリンクを作成しておきます。
sudo ln -s $HOME/.nix-profile/bin/etterminal /usr/local/bin/etterminal
接続を受け入れるときに etterminal
コマンドを実行するのですが、 ~/.nix-profile/bin
のパスが認識されないためです。
もしくは接続時にクライアント側からパス(サーバー側の etterminal
のパス)を指定します。
et nixuser@hostname --terminal-path=/home/nixuser/.nix-profile/bin/etterminal
Home Managerは便利ですが、
- OSのシステム環境
- OSのユーザー環境
- NixのHome Manager環境
- Nixの開発シェル環境
の区別がややこしいですね。
Discussion