1 { config, lib, pkgs, ... }:
4 # TODO: test configuration when building nixexpr (use -t parameter)
5 # TODO: support sqlite3 (it's deprecate?) and mysql
19 libDir = "/var/lib/bacula";
21 yes_no = bool: if bool then "yes" else "no";
22 tls_conf = tls_cfg: optionalString tls_cfg.enable (
27 ++ optional (tls_cfg.require != null) "TLS Require = ${yes_no tls_cfg.require};"
28 ++ optional (tls_cfg.certificate != null) ''TLS Certificate = "${tls_cfg.certificate}";''
29 ++ [''TLS Key = "${tls_cfg.key}";'']
30 ++ optional (tls_cfg.verifyPeer != null) "TLS Verify Peer = ${yes_no tls_cfg.verifyPeer};"
31 ++ optional (tls_cfg.allowedCN != [ ]) "TLS Allowed CN = ${concatStringsSep " " (tls_cfg.allowedCN)};"
32 ++ optional (tls_cfg.caCertificateFile != null) ''TLS CA Certificate File = "${tls_cfg.caCertificateFile}";''
36 fd_cfg = config.services.bacula-fd;
37 fd_conf = pkgs.writeText "bacula-fd.conf"
40 Name = "${fd_cfg.name}";
41 FDPort = ${toString fd_cfg.port};
42 WorkingDirectory = ${libDir};
44 ${fd_cfg.extraClientConfig}
45 ${tls_conf fd_cfg.tls}
48 ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
51 Password = ${value.password};
52 Monitor = ${value.monitor};
59 syslog = all, !skipped, !restored
60 ${fd_cfg.extraMessagesConfig}
64 sd_cfg = config.services.bacula-sd;
65 sd_conf = pkgs.writeText "bacula-sd.conf"
68 Name = "${sd_cfg.name}";
69 SDPort = ${toString sd_cfg.port};
70 WorkingDirectory = ${libDir};
72 ${sd_cfg.extraStorageConfig}
73 ${tls_conf sd_cfg.tls}
76 ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
79 Device = ${concatStringsSep ", " (map (a: "\"${a}\"") value.devices)};
80 Changer Device = ${value.changerDevice};
81 Changer Command = ${value.changerCommand};
82 ${value.extraAutochangerConfig}
84 '') sd_cfg.autochanger)}
86 ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
89 Archive Device = ${value.archiveDevice};
90 Media Type = ${value.mediaType};
91 ${value.extraDeviceConfig}
95 ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
98 Password = ${value.password};
99 Monitor = ${value.monitor};
100 ${tls_conf value.tls}
102 '') sd_cfg.director)}
106 syslog = all, !skipped, !restored
107 ${sd_cfg.extraMessagesConfig}
111 dir_cfg = config.services.bacula-dir;
112 dir_conf = pkgs.writeText "bacula-dir.conf"
115 Name = "${dir_cfg.name}";
116 Password = ${dir_cfg.password};
117 DirPort = ${toString dir_cfg.port};
118 Working Directory = ${libDir};
119 Pid Directory = /run/;
120 QueryFile = ${pkgs.bacula}/etc/query.sql;
121 ${tls_conf dir_cfg.tls}
122 ${dir_cfg.extraDirectorConfig}
133 syslog = all, !skipped, !restored
134 ${dir_cfg.extraMessagesConfig}
137 ${dir_cfg.extraConfig}
140 linkOption = name: destination: "[${name}](#opt-${builtins.replaceStrings [ "<" ">"] ["_" "_"] destination})";
141 tlsLink = destination: submodulePath: linkOption "${submodulePath}.${destination}" "${submodulePath}.${destination}";
143 tlsOptions = submodulePath: {...}:
150 Specifies if TLS should be enabled.
151 If this set to `false` TLS will be completely disabled, even if ${tlsLink "tls.require" submodulePath} is true.
155 type = types.nullOr types.bool;
158 Require TLS or TLS-PSK encryption.
159 This directive is ignored unless one of ${tlsLink "tls.enable" submodulePath} is true or TLS PSK Enable is set to `yes`.
160 If TLS is not required while TLS or TLS-PSK are enabled, then the Bacula component
161 will connect with other components either with or without TLS or TLS-PSK
163 If ${tlsLink "tls.enable" submodulePath} or TLS-PSK is enabled and TLS is required, then the Bacula
164 component will refuse any connection request that does not use TLS.
167 certificate = mkOption {
168 type = types.nullOr types.path;
171 The full path to the PEM encoded TLS certificate.
172 It will be used as either a client or server certificate,
173 depending on the connection direction.
174 This directive is required in a server context, but it may
175 not be specified in a client context if ${tlsLink "tls.verifyPeer" submodulePath} is
176 `false` in the corresponding server context.
182 The path of a PEM encoded TLS private key.
183 It must correspond to the TLS certificate.
186 verifyPeer = mkOption {
187 type = types.nullOr types.bool;
190 Verify peer certificate.
191 Instructs server to request and verify the client's X.509 certificate.
192 Any client certificate signed by a known-CA will be accepted.
193 Additionally, the client's X509 certificate Common Name must meet the value of the Address directive.
194 If ${tlsLink "tls.allowedCN" submodulePath} is used,
195 the client's x509 certificate Common Name must also correspond to
196 one of the CN specified in the ${tlsLink "tls.allowedCN" submodulePath} directive.
197 This directive is valid only for a server and not in client context.
199 Standard from Bacula is `true`.
202 allowedCN = mkOption {
203 type = types.listOf types.str;
206 Common name attribute of allowed peer certificates.
207 This directive is valid for a server and in a client context.
208 If this directive is specified, the peer certificate will be verified against this list.
209 In the case this directive is configured on a server side, the allowed
210 CN list will not be checked if ${tlsLink "tls.verifyPeer" submodulePath} is false.
213 caCertificateFile = mkOption {
214 type = types.nullOr types.path;
217 The path specifying a PEM encoded TLS CA certificate(s).
218 Multiple certificates are permitted in the file.
219 One of TLS CA Certificate File or TLS CA Certificate Dir are required in a server context, unless
220 ${tlsLink "tls.verifyPeer" submodulePath} is false, and are always required in a client context.
226 directorOptions = submodulePath:{...}:
229 password = mkOption {
233 Specifies the password that must be supplied for the default Bacula
234 Console to be authorized. The same password must appear in the
235 Director resource of the Console configuration file. For added
236 security, the password is never passed across the network but instead
237 a challenge response hash code created with the password. This
238 directive is required. If you have either /dev/random or bc on your
239 machine, Bacula will generate a random password during the
240 configuration process, otherwise it will be left blank and you must
243 The password is plain text. It is not generated through any special
244 process but as noted above, it is better to use random text for
250 type = types.enum [ "no" "yes" ];
254 If Monitor is set to `no`, this director will have
255 full access to this Storage daemon. If Monitor is set to
256 `yes`, this director will only be able to fetch the
257 current status of this Storage daemon.
259 Please note that if this director is being used by a Monitor, we
260 highly recommend to set this directive to yes to avoid serious
266 type = types.submodule (tlsOptions "${submodulePath}.director.<name>");
268 TLS Options for the Director in this Configuration.
274 autochangerOptions = {...}:
277 changerDevice = mkOption {
280 The specified name-string must be the generic SCSI device name of the
281 autochanger that corresponds to the normal read/write Archive Device
282 specified in the Device resource. This generic SCSI device name
283 should be specified if you have an autochanger or if you have a
284 standard tape drive and want to use the Alert Command (see below).
285 For example, on Linux systems, for an Archive Device name of
286 `/dev/nst0`, you would specify
287 `/dev/sg0` for the Changer Device name. Depending
288 on your exact configuration, and the number of autochangers or the
289 type of autochanger, what you specify here can vary. This directive
290 is optional. See the Using AutochangersAutochangersChapter chapter of
291 this manual for more details of using this and the following
292 autochanger directives.
296 changerCommand = mkOption {
299 The name-string specifies an external program to be called that will
300 automatically change volumes as required by Bacula. Normally, this
301 directive will be specified only in the AutoChanger resource, which
302 is then used for all devices. However, you may also specify the
303 different Changer Command in each Device resource. Most frequently,
304 you will specify the Bacula supplied mtx-changer script as follows:
306 `"/path/mtx-changer %c %o %S %a %d"`
308 and you will install the mtx on your system (found in the depkgs
309 release). An example of this command is in the default bacula-sd.conf
310 file. For more details on the substitution characters that may be
311 specified to configure your autochanger please see the
312 AutochangersAutochangersChapter chapter of this manual. For FreeBSD
313 users, you might want to see one of the several chio scripts in
314 examples/autochangers.
316 default = "/etc/bacula/mtx-changer %c %o %S %a %d";
321 type = types.listOf types.str;
324 extraAutochangerConfig = mkOption {
328 Extra configuration to be passed in Autochanger directive.
338 deviceOptions = {...}:
341 archiveDevice = mkOption {
345 The specified name-string gives the system file name of the storage
346 device managed by this storage daemon. This will usually be the
347 device file name of a removable storage device (tape drive), for
348 example `/dev/nst0` or
349 `/dev/rmt/0mbn`. For a DVD-writer, it will be for
350 example `/dev/hdc`. It may also be a directory name
351 if you are archiving to disk storage. In this case, you must supply
352 the full absolute path to the directory. When specifying a tape
353 device, it is preferable that the "non-rewind" variant of the device
358 mediaType = mkOption {
362 The specified name-string names the type of media supported by this
363 device, for example, `DLT7000`. Media type names are
364 arbitrary in that you set them to anything you want, but they must be
365 known to the volume database to keep track of which storage daemons
366 can read which volumes. In general, each different storage type
367 should have a unique Media Type associated with it. The same
368 name-string must appear in the appropriate Storage resource
369 definition in the Director's configuration file.
371 Even though the names you assign are arbitrary (i.e. you choose the
372 name you want), you should take care in specifying them because the
373 Media Type is used to determine which storage device Bacula will
374 select during restore. Thus you should probably use the same Media
375 Type specification for all drives where the Media can be freely
376 interchanged. This is not generally an issue if you have a single
377 Storage daemon, but it is with multiple Storage daemons, especially
378 if they have incompatible media.
380 For example, if you specify a Media Type of `DDS-4`
381 then during the restore, Bacula will be able to choose any Storage
382 Daemon that handles `DDS-4`. If you have an
383 autochanger, you might want to name the Media Type in a way that is
384 unique to the autochanger, unless you wish to possibly use the
385 Volumes in other drives. You should also ensure to have unique Media
386 Type names if the Media is not compatible between drives. This
387 specification is required for all devices.
389 In addition, if you are using disk storage, each Device resource will
390 generally have a different mount point or directory. In order for
391 Bacula to select the correct Device resource, each one must have a
396 extraDeviceConfig = mkOption {
400 Extra configuration to be passed in Device directive.
416 services.bacula-fd = {
421 Whether to enable the Bacula File Daemon.
426 default = "${config.networking.hostName}-fd";
427 defaultText = literalExpression ''"''${config.networking.hostName}-fd"'';
430 The client name that must be used by the Director when connecting.
431 Generally, it is a good idea to use a name related to the machine so
432 that error messages can be easily identified if you have multiple
433 Clients. This directive is required.
441 This specifies the port number on which the Client listens for
442 Director connections. It must agree with the FDPort specified in
443 the Client resource of the Director's configuration file.
447 director = mkOption {
450 This option defines director resources in Bacula File Daemon.
452 type = types.attrsOf (types.submodule (directorOptions "services.bacula-fd"));
457 type = types.submodule (tlsOptions "services.bacula-fd");
460 TLS Options for the File Daemon.
461 Important notice: The backup won't be encrypted.
465 extraClientConfig = mkOption {
469 Extra configuration to be passed in Client directive.
472 Maximum Concurrent Jobs = 20;
473 Heartbeat Interval = 30;
477 extraMessagesConfig = mkOption {
481 Extra configuration to be passed in Messages directive.
489 services.bacula-sd = {
494 Whether to enable Bacula Storage Daemon.
499 default = "${config.networking.hostName}-sd";
500 defaultText = literalExpression ''"''${config.networking.hostName}-sd"'';
503 Specifies the Name of the Storage daemon.
511 Specifies port number on which the Storage daemon listens for
512 Director connections.
516 director = mkOption {
519 This option defines Director resources in Bacula Storage Daemon.
521 type = types.attrsOf (types.submodule (directorOptions "services.bacula-sd"));
527 This option defines Device resources in Bacula Storage Daemon.
529 type = types.attrsOf (types.submodule deviceOptions);
532 autochanger = mkOption {
535 This option defines Autochanger resources in Bacula Storage Daemon.
537 type = types.attrsOf (types.submodule autochangerOptions);
540 extraStorageConfig = mkOption {
544 Extra configuration to be passed in Storage directive.
547 Maximum Concurrent Jobs = 20;
548 Heartbeat Interval = 30;
552 extraMessagesConfig = mkOption {
556 Extra configuration to be passed in Messages directive.
563 type = types.submodule (tlsOptions "services.bacula-sd");
566 TLS Options for the Storage Daemon.
567 Important notice: The backup won't be encrypted.
573 services.bacula-dir = {
578 Whether to enable Bacula Director Daemon.
583 default = "${config.networking.hostName}-dir";
584 defaultText = literalExpression ''"''${config.networking.hostName}-dir"'';
587 The director name used by the system administrator. This directive is
596 Specify the port (a positive integer) on which the Director daemon
597 will listen for Bacula Console connections. This same port number
598 must be specified in the Director resource of the Console
599 configuration file. The default is 9101, so normally this directive
600 need not be specified. This directive should not be used if you
601 specify DirAddresses (N.B plural) directive.
605 password = mkOption {
609 Specifies the password that must be supplied for a Director.
613 extraMessagesConfig = mkOption {
617 Extra configuration to be passed in Messages directive.
624 extraDirectorConfig = mkOption {
628 Extra configuration to be passed in Director directive.
631 Maximum Concurrent Jobs = 20;
632 Heartbeat Interval = 30;
636 extraConfig = mkOption {
640 Extra configuration for Bacula Director Daemon.
648 type = types.submodule (tlsOptions "services.bacula-dir");
651 TLS Options for the Director.
652 Important notice: The backup won't be encrypted.
658 config = mkIf (fd_cfg.enable || sd_cfg.enable || dir_cfg.enable) {
659 systemd.slices.system-bacula = {
660 description = "Bacula Backup System Slice";
661 documentation = [ "man:bacula(8)" "https://www.bacula.org/" ];
664 systemd.services.bacula-fd = mkIf fd_cfg.enable {
665 after = [ "network.target" ];
666 description = "Bacula File Daemon";
667 wantedBy = [ "multi-user.target" ];
668 path = [ pkgs.bacula ];
670 ExecStart = "${pkgs.bacula}/sbin/bacula-fd -f -u root -g bacula -c ${fd_conf}";
671 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
672 LogsDirectory = "bacula";
673 StateDirectory = "bacula";
674 Slice = "system-bacula.slice";
678 systemd.services.bacula-sd = mkIf sd_cfg.enable {
679 after = [ "network.target" ];
680 description = "Bacula Storage Daemon";
681 wantedBy = [ "multi-user.target" ];
682 path = [ pkgs.bacula ];
684 ExecStart = "${pkgs.bacula}/sbin/bacula-sd -f -u bacula -g bacula -c ${sd_conf}";
685 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
686 LogsDirectory = "bacula";
687 StateDirectory = "bacula";
688 Slice = "system-bacula.slice";
692 services.postgresql.enable = lib.mkIf dir_cfg.enable true;
694 systemd.services.bacula-dir = mkIf dir_cfg.enable {
695 after = [ "network.target" "postgresql.service" ];
696 description = "Bacula Director Daemon";
697 wantedBy = [ "multi-user.target" ];
698 path = [ pkgs.bacula ];
700 ExecStart = "${pkgs.bacula}/sbin/bacula-dir -f -u bacula -g bacula -c ${dir_conf}";
701 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
702 LogsDirectory = "bacula";
703 StateDirectory = "bacula";
704 Slice = "system-bacula.slice";
707 if ! test -e "${libDir}/db-created"; then
708 ${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole bacula
709 #${pkgs.postgresql}/bin/createdb --owner bacula bacula
712 ${pkgs.bacula}/etc/create_bacula_database postgresql
713 ${pkgs.bacula}/etc/make_bacula_tables postgresql
714 ${pkgs.bacula}/etc/grant_bacula_privileges postgresql
715 touch "${libDir}/db-created"
717 ${pkgs.bacula}/etc/update_bacula_tables postgresql || true
722 environment.systemPackages = [ pkgs.bacula ];
724 users.users.bacula = {
726 uid = config.ids.uids.bacula;
729 description = "Bacula Daemons user";
730 shell = "${pkgs.bash}/bin/bash";
733 users.groups.bacula.gid = config.ids.gids.bacula;