10 oct 2011
#how to integrate a daemon into nixos
in this short article i want to show how services can be added/used in nixos. i personally find the nixos way a quite easy and ‘clean’ approach!
as i integrated cntlm my goals were:
it helped a lot to look at similar scripts like the sshd integration but i also used “NixOS: A Purely functional Linux Distribution” [1] which is describing most aspects which are needed to get a service up and running.
seen as a developer one has to write two nix expressions:
seen as a user one has to modify only one nix expression:
this nix expression describes the cntlm software and is quite simple as it basically fetches the software/compiles it/installs it into the system. however, a user does not have to install this software using:
# nix-env -i cntlm
still this would be possible, and a normal user/root user could use the software in his profile this way.
anyway here is the script:
1 { stdenv, fetchurl, which}:
2
3 stdenv.mkDerivation {
4 name = "cntlm-0.35.1";
5
6 src = fetchurl {
7 url = mirror://sourceforge/cntlm/cntlm-0.35.1.tar.gz;
8 sha256 = "7b3fb7184e72cc3f1743bb8e503a5305e96458bc630a7e1ebfc9f3c07ffa6c5e";
9 };
10
11 buildInputs = [ which ];
12
13 installPhase = ''
14 ensureDir $out/bin; cp cntlm $out/bin/;
15 ensureDir $out/share/; cp COPYRIGHT README VERSION doc/cntlm.conf $out/share/;
16 ensureDir $out/man/; cp doc/cntlm.1 $out/man/;
17 '';
18
19 meta = {
20 description = "Cntlm is an NTLM/NTLMv2 authenticating HTTP proxy";
21 homepage = http://cntlm.sourceforge.net/;
22 license = stdenv.lib.licenses.gpl2;
23 maintainers = [ stdenv.lib.maintainers.qknight ];
24 };
25 }
the only point of interest might be the buildInputs (line 11) which includes which. in this build script ‘which gcc’ is used to test if gcc is installed.
this expression is used to integrate cntlm as a system service.
1 { config, pkgs, ... }:
2
3 with pkgs.lib;
4
5 let
6
7 cfg = config.services.cntlm;
8 uid = config.ids.uids.cntlm;
9
10 in
11
12 {
13
14 options = {
15
16 services.cntlm= {
17
18 enable = mkOption {
19 default = false;
20 description = ''
21 Whether to enable the cntlm, which start a local proxy.
22 '';
23 };
24
25 username = mkOption {
26 description = ''
27 Proxy account name, without the possibility to include domain name ('at' sign is interpreted literally).
28 '';
29 };
30
31 domain = mkOption {
32 description = ''Proxy account domain/workgroup name.'';
33 };
34
35 password = mkOption {
36 default = "/etc/cntlm.password";
37 type = with pkgs.lib.types; string;
38 description = ''Proxy account password. Note: use chmod 0600 on /etc/cntlm.password for security.'';
39 };
40
41 netbios_hostname = mkOption {
42 default = config.networking.hostName;
43 description = ''
44 The hostname of your workstation.
45 '';
46 };
47
48 proxy = mkOption {
49 description = ''
50 A list of NTLM/NTLMv2 authenticating HTTP proxies.
51
52 Parent proxy, which requires authentication. The same as proxy on the command-line, can be used more than once to specify unlimited
53 number of proxies. Should one proxy fail, cntlm automatically moves on to the next one. The connect request fails only if the whole
54 list of proxies is scanned and (for each request) and found to be invalid. Command-line takes precedence over the configuration file.
55 '';
56 };
57
58 port = mkOption {
59 default = [3128];
60 description = "Specifies on which ports the cntlm daemon listens.";
61 };
62
63 extraConfig = mkOption {
64 default = "";
65 description = "Verbatim contents of cntlm.conf.";
66 };
67
68 };
69
70 };
71
72
73 ###### implementation
74
75 config = mkIf config.services.cntlm.enable {
76 users.extraUsers = singleton {
77 name = "cntlm";
78 description = "cntlm system-wide daemon";
79 home = "/var/empty";
80 };
81
82 jobs.cntlm = {
83 description = "cntlm is an NTLM / NTLM Session Response / NTLMv2 authenticating HTTP proxy.";
84 startOn = "started network-interfaces";
85 environment = {
86 };
87
88 preStart = '' '';
89
90 daemonType = "fork";
91
92 exec =
93 ''
94 ${pkgs.cntlm}/bin/cntlm -U cntlm \
95 -c ${pkgs.writeText "cntlm_config" cfg.extraConfig}
96 '';
97 };
98
99 services.cntlm.extraConfig =
100 ''
101 # Cntlm Authentication Proxy Configuration
102 Username ${cfg.username}
103 Domain ${cfg.domain}
104 Password ${cfg.password}
105 Workstation ${cfg.netbios_hostname}
106 ${concatMapStrings (entry: "Proxy ${entry}\n") cfg.proxy}
107
108 ${concatMapStrings (port: ''
109 Listen ${toString port}
110 '') cfg.port}
111 '';
112 };
113 }
notable parts are:
cfg.proxy = [ “foo” “bar” “baz” ];
is transformed into:
a user has to append this configuration into /etc/nixos/configuration.nix and cntlm will be installed/configured and started
services.cntlm = {
enable=true;
username="myusername";
domain="mydomain";
proxy=[ "192.168.3.5:1234" ];
};
in contrast to most other distributions nixos makes not only packaging subject to a ‘clean’ package management but also configuration management (/etc stuff) and runtime management. this is a very clean design helping to avoid lots of pitfalls.