8 cfg = config.services.keter;
9 yaml = pkgs.formats.yaml { };
13 maintainers = with lib.maintainers; [ jappie ];
17 (lib.mkRenamedOptionModule [ "services" "keter" "keterRoot" ] [ "services" "keter" "root" ])
18 (lib.mkRenamedOptionModule [ "services" "keter" "keterPackage" ] [ "services" "keter" "package" ])
21 options.services.keter = {
22 enable = lib.mkEnableOption ''
23 keter, a web app deployment manager.
24 Note that this module only support loading of webapps:
25 Keep an old app running and swap the ports when the new one is booted
30 default = "/var/lib/keter";
31 description = "Mutable state folder for keter";
34 package = lib.mkOption {
35 type = lib.types.package;
36 default = pkgs.haskellPackages.keter;
37 defaultText = lib.literalExpression "pkgs.haskellPackages.keter";
38 description = "The keter package to be used";
41 globalKeterConfig = lib.mkOption {
42 type = lib.types.submodule {
43 freeformType = yaml.type;
45 ip-from-header = lib.mkOption {
47 type = lib.types.bool;
48 description = "You want that ip-from-header in the nginx setup case. It allows nginx setting the original ip address rather then it being localhost (due to reverse proxying)";
50 listeners = lib.mkOption {
57 type = lib.types.listOf (
65 type = lib.types.port;
72 You want that ip-from-header in
74 It allows nginx setting the original ip address rather
75 then it being localhost (due to reverse proxying).
76 However if you configure keter to accept connections
77 directly you may want to set this to false.'';
79 rotate-logs = lib.mkOption {
81 type = lib.types.bool;
83 emits keter logs and it's applications to stderr.
84 which allows journald to capture them.
85 Set to true to let keter put the logs in files
86 (useful on non systemd systems, this is the old approach
87 where keter handled log management)'';
91 description = "Global config for keter, see <https://github.com/snoyberg/keter/blob/master/etc/keter-config.yaml> for reference";
95 appName = lib.mkOption {
98 description = "The name keter assigns to this bundle";
101 executable = lib.mkOption {
102 type = lib.types.path;
103 description = "The executable to be run";
106 domain = lib.mkOption {
107 type = lib.types.str;
108 default = "example.com";
109 description = "The domain keter will bind to";
112 publicScript = lib.mkOption {
113 type = lib.types.str;
116 Allows loading of public environment variables,
117 these are emitted to the log so it shouldn't contain secrets.
119 example = "ADMIN_EMAIL=hi@example.com";
122 secretScript = lib.mkOption {
123 type = lib.types.str;
125 description = "Allows loading of private environment variables";
126 example = "MY_AWS_KEY=$(cat /run/keys/AWS_ACCESS_KEY_ID)";
132 config = lib.mkIf cfg.enable (
134 incoming = "${cfg.root}/incoming";
136 globalKeterConfigFile = pkgs.writeTextFile {
137 name = "keter-config.yml";
138 text = (lib.generators.toYAML { } (cfg.globalKeterConfig // { root = cfg.root; }));
141 # If things are expected to change often, put it in the bundle!
142 bundle = pkgs.callPackage ./bundle.nix (
145 keterExecutable = executable;
146 keterDomain = cfg.bundle.domain;
150 # This indirection is required to ensure the nix path
151 # gets copied over to the target machine in remote deployments.
152 # Furthermore, it's important that we use exec to
153 # run the binary otherwise we get process leakage due to this
154 # being executed on every change.
155 executable = pkgs.writeShellScript "bundle-wrapper" ''
157 ${cfg.bundle.secretScript}
159 ${cfg.bundle.publicScript}
160 exec ${cfg.bundle.executable}
165 systemd.services.keter = {
166 description = "keter app loader";
170 ${lib.getExe cfg.package} ${globalKeterConfigFile};
189 # On deploy this will load our app, by moving it into the incoming dir
190 # If the bundle content changes, this will run again.
191 # Because the bundle content contains the nix path to the executable,
192 # we inherit nix based cache busting.
193 systemd.services.load-keter-bundle = {
194 description = "load keter bundle into incoming folder";
195 after = [ "keter.service" ];
196 wantedBy = [ "multi-user.target" ];
197 # we can't override keter bundles because it'll stop the previous app
198 # https://github.com/snoyberg/keter#deploying
201 cp ${bundle}/bundle.tar.gz.keter ${incoming}/${cfg.bundle.appName}.keter
205 cfg.bundle.executable
206 ]; # this is a hack to get the executable copied over to the machine.