···7273- [LibreNMS](https://www.librenms.org), a auto-discovering PHP/MySQL/SNMP based network monitoring. Available as [services.librenms](#opt-services.librenms.enable).
740075- [sitespeed-io](https://sitespeed.io), a tool that can generate metrics (timings, diagnostics) for websites. Available as [services.sitespeed-io](#opt-services.sitespeed-io.enable).
7677- [stalwart-mail](https://stalw.art), an all-in-one email server (SMTP, IMAP, JMAP). Available as [services.stalwart-mail](#opt-services.stalwart-mail.enable).
···7273- [LibreNMS](https://www.librenms.org), a auto-discovering PHP/MySQL/SNMP based network monitoring. Available as [services.librenms](#opt-services.librenms.enable).
7475+- [Livebook](https://livebook.dev/), an interactive notebook with support for Elixir, graphs, machine learning, and more.
76+77- [sitespeed-io](https://sitespeed.io), a tool that can generate metrics (timings, diagnostics) for websites. Available as [services.sitespeed-io](#opt-services.sitespeed-io.enable).
7879- [stalwart-mail](https://stalw.art), an all-in-one email server (SMTP, IMAP, JMAP). Available as [services.stalwart-mail](#opt-services.stalwart-mail.enable).
···1+# Livebook {#module-services-livebook}
2+3+[Livebook](https://livebook.dev/) is a web application for writing
4+interactive and collaborative code notebooks.
5+6+## Basic Usage {#module-services-livebook-basic-usage}
7+8+Enabling the `livebook` service creates a user
9+[`systemd`](https://www.freedesktop.org/wiki/Software/systemd/) unit
10+which runs the server.
11+12+```
13+{ ... }:
14+15+{
16+ services.livebook = {
17+ enableUserService = true;
18+ port = 20123;
19+ # See note below about security
20+ environmentFile = pkgs.writeText "livebook.env" ''
21+ LIVEBOOK_PASSWORD = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
22+ '';
23+ };
24+}
25+```
26+27+::: {.note}
28+29+The Livebook server has the ability to run any command as the user it
30+is running under, so securing access to it with a password is highly
31+recommended.
32+33+Putting the password in the Nix configuration like above is an easy
34+way to get started but it is not recommended in the real world because
35+the `livebook.env` file will be added to the world-readable Nix store.
36+A better approach would be to put the password in some secure
37+user-readable location and set `environmentFile = /home/user/secure/livebook.env`.
38+39+:::
···1+{ config, lib, pkgs, ... }:
2+3+with lib;
4+let
5+ cfg = config.services.livebook;
6+in
7+{
8+ options.services.livebook = {
9+ # Since livebook doesn't have a granular permission system (a user
10+ # either has access to all the data or none at all), the decision
11+ # was made to run this as a user service. If that changes in the
12+ # future, this can be changed to a system service.
13+ enableUserService = mkEnableOption "a user service for Livebook";
14+15+ environmentFile = mkOption {
16+ type = types.path;
17+ description = lib.mdDoc ''
18+ Environment file as defined in {manpage}`systemd.exec(5)` passed to the service.
19+20+ This must contain at least `LIVEBOOK_PASSWORD` or
21+ `LIVEBOOK_TOKEN_ENABLED=false`. See `livebook server --help`
22+ for other options.'';
23+ };
24+25+ erlang_node_short_name = mkOption {
26+ type = with types; nullOr str;
27+ default = null;
28+ example = "livebook";
29+ description = "A short name for the distributed node.";
30+ };
31+32+ erlang_node_name = mkOption {
33+ type = with types; nullOr str;
34+ default = null;
35+ example = "livebook@127.0.0.1";
36+ description = "The name for the app distributed node.";
37+ };
38+39+ port = mkOption {
40+ type = types.port;
41+ default = 8080;
42+ description = "The port to start the web application on.";
43+ };
44+45+ address = mkOption {
46+ type = types.str;
47+ default = "127.0.0.1";
48+ description = lib.mdDoc ''
49+ The address to start the web application on. Must be a valid IPv4 or
50+ IPv6 address.
51+ '';
52+ };
53+54+ options = mkOption {
55+ type = with types; attrsOf str;
56+ default = { };
57+ description = lib.mdDoc ''
58+ Additional options to pass as command-line arguments to the server.
59+ '';
60+ example = literalExpression ''
61+ {
62+ cookie = "a value shared by all nodes in this cluster";
63+ }
64+ '';
65+ };
66+ };
67+68+ config = mkIf cfg.enableUserService {
69+ systemd.user.services.livebook = {
70+ serviceConfig = {
71+ Restart = "always";
72+ EnvironmentFile = cfg.environmentFile;
73+ ExecStart =
74+ let
75+ args = lib.cli.toGNUCommandLineShell { } ({
76+ inherit (cfg) port;
77+ ip = cfg.address;
78+ name = cfg.erlang_node_name;
79+ sname = cfg.erlang_node_short_name;
80+ } // cfg.options);
81+ in
82+ "${pkgs.livebook}/bin/livebook server ${args}";
83+ };
84+ path = [ pkgs.bash ];
85+ wantedBy = [ "default.target" ];
86+ };
87+ };
88+89+ meta.doc = ./livebook.md;
90+}