Creating a service on NixOS from a flake

(This post is a follow-up to Packaging a Haskell project as a Nix flake.)

Since I was able to nix build my silly bot, I wanted to deploy it as a service on my NixOS server. This turned out to be quite easy! A helpful person on Mastodon said that I probably wanted to do something like this:

systemd.services.myprogram = { serviceConfig.ExecStart = "${my-binary}/bin/my-binary"; };

The only problem was getting a binary onto my server somehow. I now had a flake for the project, and some searching led me to getFlake, which can take a github/sourcehut/etc. git URL, such that the following would be enought to include this flake in my system configuration:

(builtins.getFlake
          "github:ehamberg/tribot/984b19ede065326a7f6ef31982c06fab9e03d72b")

This flake has a set of packages and by using the builtins.currentSystem function I can get the default package for the correct system:

(builtins.getFlake
          "github:ehamberg/tribot/984b19ede065326a7f6ef31982c06fab9e03d72b").packages.${builtins.currentSystem}.default

Once I had this, I could finally create my serviceConfig with an ExecStart pointing to the binary built from my flake:

  systemd.services.tribot = {
    after = [ "network.target" ];
    wantedBy = [ "multi-user.target" ];

    serviceConfig = {
      User = "tribot";
      Group = "tribot";
      WorkingDirectory = "/home/tribot";

      ExecStart = let
        tribot = (builtins.getFlake
          "github:ehamberg/tribot/984b19ede065326a7f6ef31982c06fab9e03d72b").packages.${builtins.currentSystem}.default;
      in "${tribot}/bin/tribot tribot irc.ipv4.libera.chat tribot 'secret' ehamberg '#tribot'";
      Restart = "on-failure";
      RestartSec = "10";
    };
  };

The final services/tribot.nix:

{ pkgs, ... }: {
  users.users.tribot = {
    isNormalUser = true;
    description = "tribot";
    group = "tribot";
  };
  users.groups.tribot = { };

  systemd.services.tribot = {
    after = [ "network.target" ];
    wantedBy = [ "multi-user.target" ];

    serviceConfig = {
      User = "tribot";
      Group = "tribot";
      WorkingDirectory = "/home/tribot";

      ExecStart = let
        tribot = (builtins.getFlake
          "github:ehamberg/tribot/984b19ede065326a7f6ef31982c06fab9e03d72b").packages.${builtins.currentSystem}.default;
      in "${tribot}/bin/tribot tribot irc.ipv4.libera.chat tribot 'secret' ehamberg '#tribot'";
      Restart = "on-failure";
      RestartSec = "10";
    };
  };
}

This can then be added to the imports array in configuration.nix and a nixos-rebuild switch later ’tis live!