最近XにてNixやNixOSの話題が出ていたので、Bunで実装したbotをNixOSにデプロイしてみました。
サンプルリポジトリはこちら。
/etc/nixos以下をflakeで管理しているNixOSまず、npmパッケージのディレクトリ内でnix flake initを実行して、flakeリポジトリを初期化します。
flake.nixの内容を次のようにします。
{
description = "bun-nixos-sample";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
};
outputs =
{ self, nixpkgs, ... }:
let
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
];
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems f;
in
{
packages = forAllSystems (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
node_modules = pkgs.stdenv.mkDerivation {
name = "bun-nixos-sample-node-modules";
src = pkgs.lib.cleanSourceWith {
src = ./.;
filter =
path: type:
builtins.elem (baseNameOf path) [
"package.json"
"bun.lock"
];
};
outputHashMode = "recursive";
outputHashAlgo = "sha256";
outputHash = "";
nativeBuildInputs = [ pkgs.bun ];
buildPhase = ''
export HOME=$TMPDIR
bun install --frozen-lockfile
'';
installPhase = ''
mkdir -p $out
cp -r node_modules $out/
'';
};
in
{
default = pkgs.stdenv.mkDerivation {
pname = "bun-nixos-sample";
version = "0.1.0";
src = pkgs.lib.cleanSource ./.;
nativeBuildInputs = [
pkgs.bun
pkgs.makeWrapper
];
buildPhase = ''
export HOME=$TMPDIR
ln -s ${node_modules}/node_modules ./node_modules
bun build --target=bun ./index.ts --outdir ./dist
'';
installPhase = ''
mkdir -p $out/lib/bun-nixos-sample
cp dist/index.js $out/lib/bun-nixos-sample/
mkdir -p $out/bin
makeWrapper ${pkgs.bun}/bin/bun $out/bin/bun-nixos-sample \
--add-flags "$out/lib/bun-nixos-sample/index.js"
'';
};
}
);
nixosModules.default =
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.bun-nixos-sample;
in
{
options.services.bun-nixos-sample = {
enable = lib.mkEnableOption "bun-nixos-sample service";
package = lib.mkOption {
type = lib.types.package;
default = self.packages.${pkgs.system}.default;
description = "The bun-nixos-sample package to use.";
};
};
config = lib.mkIf cfg.enable {
users.users.bun-nixos-sample = {
isSystemUser = true;
group = "bun-nixos-sample";
description = "bun-nixos-sample service user";
};
users.groups.bun-nixos-sample = { };
systemd.services.bun-nixos-sample = {
description = "bun-nixos-sample";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${cfg.package}/bin/bun-nixos-sample";
Restart = "on-failure";
RestartSec = 10;
User = "bun-nixos-sample";
Group = "bun-nixos-sample";
}
// {
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
RestrictNamespaces = true;
RestrictSUIDSGID = true;
MemoryDenyWriteExecute = false;
};
};
};
};
devShells = forAllSystems (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
default = pkgs.mkShell {
packages = with pkgs; [
bun
typescript
];
};
}
);
};
}この状態で*.nixをgit addして、nix buildを実行します。
すると、次のようなエラーが出るはずです。
warning: Git tree '/home/user/projects/bun-nixos-sample' has uncommitted changes
warning: found empty hash, assuming 'sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='
error: hash mismatch in fixed-output derivation '/nix/store/nb17j30gpflnnng66244x0d19frl3ff7-bun-nixos-sample-node-modules.drv':
specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
got: sha256-9ruhMeqyGUyPT891SVKnwPPtURwgBXGWTmob8mtnJhs=
error: Cannot build '/nix/store/igcrk3d3piqkrxplazl73hcmfrl9b1h5-bun-nixos-sample-0.1.0.drv'.
Reason: 1 dependency failed.
Output paths:
/nix/store/j9xz2qg6qwrlqf3flp9s6mgk08h8b4bh-bun-nixos-sample-0.1.0
❌ git+file:///home/user/projects/bun-nixos-sample#
error: Build failed due to failed dependencygot に表示されている値をflake.nixのoutputHashに入力して、再度nix buildすると成功するはずです。
このflake.nixではdevShellを使っているので、nix developを実行すると本番環境と同じバージョンのBunで開発できます。
direnvを導入していればuse flakeを.envrcに記述すると、シェル起動時に自動的にdevShellに入れます。
パッケージがプライベートリポジトリの場合、デプロイの前にNixOSのSSH公開鍵をGitHubに登録する必要があります。
ssh-keygen -t ed25519 -f /root/.ssh/github-deploy -N '' -C 'nixos-deploy'
cat /root/.ssh/github-deploy.pub表示された公開鍵をGitHubに登録したら、NixOSがGitHubへのSSH接続にその鍵を使うように設定します。
cat >> /root/.ssh/config << 'EOF'
Host github.com
IdentityFile /root/.ssh/github-deploy
EOF
ssh-keyscan github.com >> /root/.ssh/known_hosts 2>/dev/nullNixパッケージを作成したので、NixOSでは/etc/nixos以下のファイルを編集してnixos-rebuildするだけでデプロイできます。
まず、flake.nixを編集して、Gitリポジトリをパッケージとして読み込ませます。
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
bun-nixos-sample = {
url = "git+ssh://git@github.com/mopeneko/bun-nixos-sample.git";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { self, nixpkgs, bun-nixos-sample }: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
bun-nixos-sample.nixosModules.default
];
};
};
}次に、configuration.nixにサービスの有効化の設定を追記します。
services.bun-nixos-sample.enable = true;最後にNixOSに変更を反映させると、botがsystemdサービスとして実行されます。
nixos-rebuild switch --flake .#
Cloud RunやScalewayなどにデプロイするとベンダー固有の設定が生まれたり、VPSではgit cloneして、systemdサービスファイルを作成して実行する必要があったり…
NixOSであれば、どんなクラウドプロバイダーでも設定ファイルを書き換えるだけでパッケージの配置からsystemdサービスの実行までを行えるので便利そうです。
しかし、私は1つのbotだけを動かしているので、正直オーバースペックだと感じています…。
今後botが増えてきたら変わるかもしれないです。
実際のbotではsops-nixを用いてシークレット管理をしているので、これは次回解説します。