···141142- `services.clamsmtp` is unmaintained and was removed from Nixpkgs.
14300144- `services.dependency-track` removed its configuration of the JVM heap size. This lets the JVM choose its maximum heap size automatically, which should work much better in practice for most users. For deployments on systems with little RAM, it may now be necessary to manually configure a maximum heap size using {option}`services.dependency-track.javaArgs`.
145146- `services.dnscrypt-proxy2` gains a `package` option to specify dnscrypt-proxy package to use.
···141142- `services.clamsmtp` is unmaintained and was removed from Nixpkgs.
143144+- `prosody` gained a config check option named `services.prosody.checkConfig` which runs `prosodyctl check config` and is turned on by default.
145+146- `services.dependency-track` removed its configuration of the JVM heap size. This lets the JVM choose its maximum heap size automatically, which should work much better in practice for most users. For deployments on systems with little RAM, it may now be necessary to manually configure a maximum heap size using {option}`services.dependency-track.javaArgs`.
147148- `services.dnscrypt-proxy2` gains a `package` option to specify dnscrypt-proxy package to use.
+340-353
nixos/modules/services/networking/prosody.nix
···9let
10 cfg = config.services.prosody;
1112- sslOpts =
13- { ... }:
14- {
0001516- options = {
00001718- key = mkOption {
19- type = types.path;
20- description = "Path to the key file.";
21- };
22-23- # TODO: rename to certificate to match the prosody config
24- cert = mkOption {
25- type = types.path;
26- description = "Path to the certificate file.";
27- };
28-29- extraOptions = mkOption {
30- type = types.attrs;
31- default = { };
32- description = "Extra SSL configuration options.";
33- };
34-35 };
36 };
03738 discoOpts = {
39 options = {
···301 };
302 '';
303304- mucOpts =
305- { ... }:
306- {
307- options = {
308- domain = mkOption {
309- type = types.str;
310- description = "Domain name of the MUC";
311- };
312- name = mkOption {
313- type = types.str;
314- description = "The name to return in service discovery responses for the MUC service itself";
315- default = "Prosody Chatrooms";
316- };
317- restrictRoomCreation = mkOption {
318- type = types.enum [
319- true
320- false
321- "admin"
322- "local"
323- ];
324- default = false;
325- description = "Restrict room creation to server admins";
326- };
327- maxHistoryMessages = mkOption {
328- type = types.int;
329- default = 20;
330- description = "Specifies a limit on what each room can be configured to keep";
331- };
332- roomLocking = mkOption {
333- type = types.bool;
334- default = true;
335- description = ''
336- Enables room locking, which means that a room must be
337- configured before it can be used. Locked rooms are invisible
338- and cannot be entered by anyone but the creator
339- '';
340- };
341- roomLockTimeout = mkOption {
342- type = types.int;
343- default = 300;
344- description = ''
345- Timeout after which the room is destroyed or unlocked if not
346- configured, in seconds
347- '';
348- };
349- tombstones = mkOption {
350- type = types.bool;
351- default = true;
352- description = ''
353- When a room is destroyed, it leaves behind a tombstone which
354- prevents the room being entered or recreated. It also allows
355- anyone who was not in the room at the time it was destroyed
356- to learn about it, and to update their bookmarks. Tombstones
357- prevents the case where someone could recreate a previously
358- semi-anonymous room in order to learn the real JIDs of those
359- who often join there.
360- '';
361- };
362- tombstoneExpiry = mkOption {
363- type = types.int;
364- default = 2678400;
365- description = ''
366- This settings controls how long a tombstone is considered
367- valid. It defaults to 31 days. After this time, the room in
368- question can be created again.
369- '';
370- };
371- allowners_muc = mkOption {
372- type = types.bool;
373- default = false;
374- description = ''
375- Add module allowners, any user in chat is able to
376- kick other. Usefull in jitsi-meet to kick ghosts.
377- '';
378- };
379- vcard_muc = mkOption {
380- type = types.bool;
381- default = true;
382- description = "Adds the ability to set vCard for Multi User Chat rooms";
383- };
384385- # Extra parameters. Defaulting to prosody default values.
386- # Adding them explicitly to make them visible from the options
387- # documentation.
388- #
389- # See https://prosody.im/doc/modules/mod_muc for more details.
390- roomDefaultPublic = mkOption {
391- type = types.bool;
392- default = true;
393- description = "If set, the MUC rooms will be public by default.";
394- };
395- roomDefaultMembersOnly = mkOption {
396- type = types.bool;
397- default = false;
398- description = "If set, the MUC rooms will only be accessible to the members by default.";
399- };
400- roomDefaultModerated = mkOption {
401- type = types.bool;
402- default = false;
403- description = "If set, the MUC rooms will be moderated by default.";
404- };
405- roomDefaultPublicJids = mkOption {
406- type = types.bool;
407- default = false;
408- description = "If set, the MUC rooms will display the public JIDs by default.";
409- };
410- roomDefaultChangeSubject = mkOption {
411- type = types.bool;
412- default = false;
413- description = "If set, the rooms will display the public JIDs by default.";
414- };
415- roomDefaultHistoryLength = mkOption {
416- type = types.int;
417- default = 20;
418- description = "Number of history message sent to participants by default.";
419- };
420- roomDefaultLanguage = mkOption {
421- type = types.str;
422- default = "en";
423- description = "Default room language.";
424- };
425- extraConfig = mkOption {
426- type = types.lines;
427- default = "";
428- description = "Additional MUC specific configuration";
429- };
430 };
431 };
0432433- uploadHttpOpts =
434- { ... }:
435- {
436- options = {
437- domain = mkOption {
438- type = types.nullOr types.str;
439- description = "Domain name for the http-upload service";
440- };
441- uploadFileSizeLimit = mkOption {
442- type = types.str;
443- default = "50 * 1024 * 1024";
444- description = "Maximum file size, in bytes. Defaults to 50MB.";
445- };
446- uploadExpireAfter = mkOption {
447- type = types.str;
448- default = "60 * 60 * 24 * 7";
449- description = "Max age of a file before it gets deleted, in seconds.";
450- };
451- userQuota = mkOption {
452- type = types.nullOr types.int;
453- default = null;
454- example = 1234;
455- description = ''
456- Maximum size of all uploaded files per user, in bytes. There
457- will be no quota if this option is set to null.
458- '';
459- };
460- httpUploadPath = mkOption {
461- type = types.str;
462- description = ''
463- Directory where the uploaded files will be stored when the http_upload module is used.
464- By default, uploaded files are put in a sub-directory of the default Prosody storage path (usually /var/lib/prosody).
465- '';
466- default = "/var/lib/prosody";
467- };
468 };
469 };
0470471- httpFileShareOpts =
472- { ... }:
473- {
474- freeformType =
475- with types;
476- let
477- atom = oneOf [
478- int
479- bool
480- str
481- (listOf atom)
482- ];
483- in
484- attrsOf (nullOr atom)
485- // {
486- description = "int, bool, string or list of them";
487- };
488- options.domain = mkOption {
489- type = with types; nullOr str;
490- description = "Domain name for a http_file_share service.";
491 };
000492 };
0493494- vHostOpts =
495- { ... }:
496- {
0000000000000000497498- options = {
000000499500- # TODO: require attribute
501- domain = mkOption {
502- type = types.str;
503- description = "Domain name";
000000504 };
000000000000000000000505506- enabled = mkOption {
507- type = types.bool;
508- default = false;
509- description = "Whether to enable the virtual host";
510- };
511512- ssl = mkOption {
513- type = types.nullOr (types.submodule sslOpts);
514- default = null;
515- description = "Paths to SSL files";
516- };
517518- extraConfig = mkOption {
519- type = types.lines;
520- default = "";
521- description = "Additional virtual host specific configuration";
522- };
52300000524 };
525526- };
00527528-in
529530-{
531532- ###### interface
000533534- options = {
000000535536- services.prosody = {
5370000000000000000000000000000000000000000000000000538 enable = mkOption {
539 type = types.bool;
540 default = false;
541 description = "Whether to enable the prosody server";
0000000542 };
543544 xmppComplianceSuite = mkOption {
···818 }
819 '';
820 };
821-822 };
823 };
824825- ###### implementation
826-827 config = mkIf cfg.enable {
828-829 assertions =
830 let
831 genericErrMsg = ''
···860861 environment.systemPackages = [ cfg.package ];
862863- environment.etc."prosody/prosody.cfg.lua".text =
864- let
865- httpDiscoItems =
866- optional (cfg.uploadHttp != null) {
867- url = cfg.uploadHttp.domain;
868- description = "HTTP upload endpoint";
869 }
870- ++ optional (cfg.httpFileShare != null) {
871- url = cfg.httpFileShare.domain;
872- description = "HTTP file share endpoint";
873- };
874- mucDiscoItems = builtins.foldl' (
875- acc: muc:
876- [
877- {
878- url = muc.domain;
879- description = "${muc.domain} MUC endpoint";
880- }
881- ]
882- ++ acc
883- ) [ ] cfg.muc;
884- discoItems = cfg.disco_items ++ httpDiscoItems ++ mucDiscoItems;
885- in
886- ''
887-888- pidfile = "/run/prosody/prosody.pid"
889-890- log = ${cfg.log}
891-892- data_path = "${cfg.dataDir}"
893- plugin_paths = {
894- ${lib.concatStringsSep ", " (map (n: "\"${n}\"") cfg.extraPluginPaths)}
895- }
896-897- ${optionalString (cfg.ssl != null) (createSSLOptsStr cfg.ssl)}
898-899- admins = ${toLua cfg.admins}
900-901- modules_enabled = {
902-903- ${lib.concatStringsSep "\n " (
904- lib.mapAttrsToList (name: val: optionalString val "${toLua name};") cfg.modules
905- )}
906- ${lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.package.communityModules)}
907- ${lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.extraModules)}
908- };
909-910- disco_items = {
911- ${lib.concatStringsSep "\n" (builtins.map (x: ''{ "${x.url}", "${x.description}"};'') discoItems)}
912- };
913-914- allow_registration = ${toLua cfg.allowRegistration}
915-916- c2s_require_encryption = ${toLua cfg.c2sRequireEncryption}
917-918- s2s_require_encryption = ${toLua cfg.s2sRequireEncryption}
919-920- s2s_secure_auth = ${toLua cfg.s2sSecureAuth}
921-922- s2s_insecure_domains = ${toLua cfg.s2sInsecureDomains}
923-924- s2s_secure_domains = ${toLua cfg.s2sSecureDomains}
925-926- authentication = ${toLua cfg.authentication}
927-928- http_interfaces = ${toLua cfg.httpInterfaces}
929-930- https_interfaces = ${toLua cfg.httpsInterfaces}
931-932- http_ports = ${toLua cfg.httpPorts}
933-934- https_ports = ${toLua cfg.httpsPorts}
935-936- ${cfg.extraConfig}
937-938- ${lib.concatMapStrings (muc: ''
939- Component ${toLua muc.domain} "muc"
940- modules_enabled = { "muc_mam"; ${optionalString muc.vcard_muc ''"vcard_muc";''} ${optionalString muc.allowners_muc ''"muc_allowners";''} }
941- name = ${toLua muc.name}
942- restrict_room_creation = ${toLua muc.restrictRoomCreation}
943- max_history_messages = ${toLua muc.maxHistoryMessages}
944- muc_room_locking = ${toLua muc.roomLocking}
945- muc_room_lock_timeout = ${toLua muc.roomLockTimeout}
946- muc_tombstones = ${toLua muc.tombstones}
947- muc_tombstone_expiry = ${toLua muc.tombstoneExpiry}
948- muc_room_default_public = ${toLua muc.roomDefaultPublic}
949- muc_room_default_members_only = ${toLua muc.roomDefaultMembersOnly}
950- muc_room_default_moderated = ${toLua muc.roomDefaultModerated}
951- muc_room_default_public_jids = ${toLua muc.roomDefaultPublicJids}
952- muc_room_default_change_subject = ${toLua muc.roomDefaultChangeSubject}
953- muc_room_default_history_length = ${toLua muc.roomDefaultHistoryLength}
954- muc_room_default_language = ${toLua muc.roomDefaultLanguage}
955- ${muc.extraConfig}
956- '') cfg.muc}
957-958- ${lib.optionalString (cfg.uploadHttp != null) ''
959- Component ${toLua cfg.uploadHttp.domain} "http_upload"
960- http_upload_file_size_limit = ${cfg.uploadHttp.uploadFileSizeLimit}
961- http_upload_expire_after = ${cfg.uploadHttp.uploadExpireAfter}
962- ${lib.optionalString (
963- cfg.uploadHttp.userQuota != null
964- ) "http_upload_quota = ${toLua cfg.uploadHttp.userQuota}"}
965- http_upload_path = ${toLua cfg.uploadHttp.httpUploadPath}
966- ''}
967-968- ${lib.optionalString (cfg.httpFileShare != null) ''
969- Component ${toLua cfg.httpFileShare.domain} "http_file_share"
970- ${settingsToLua " http_file_share_" (cfg.httpFileShare // { domain = null; })}
971- ''}
972-973- ${lib.concatStringsSep "\n" (
974- lib.mapAttrsToList (n: v: ''
975- VirtualHost "${v.domain}"
976- enabled = ${boolToString v.enabled};
977- ${optionalString (v.ssl != null) (createSSLOptsStr v.ssl)}
978- ${v.extraConfig}
979- '') cfg.virtualHosts
980- )}
981- '';
982983 users.users.prosody = mkIf (cfg.user == "prosody") {
984 uid = config.ids.uids.prosody;
···1025 })
1026 ];
1027 };
1028-1029 };
10301031 meta.doc = ./prosody.md;
···9let
10 cfg = config.services.prosody;
1112+ sslOpts = _: {
13+ options = {
14+ key = mkOption {
15+ type = types.path;
16+ description = "Path to the key file.";
17+ };
1819+ # TODO: rename to certificate to match the prosody config
20+ cert = mkOption {
21+ type = types.path;
22+ description = "Path to the certificate file.";
23+ };
2425+ extraOptions = mkOption {
26+ type = types.attrs;
27+ default = { };
28+ description = "Extra SSL configuration options.";
000000000000029 };
30 };
31+ };
3233 discoOpts = {
34 options = {
···296 };
297 '';
298299+ mucOpts = _: {
300+ options = {
301+ domain = mkOption {
302+ type = types.str;
303+ description = "Domain name of the MUC";
304+ };
305+ name = mkOption {
306+ type = types.str;
307+ description = "The name to return in service discovery responses for the MUC service itself";
308+ default = "Prosody Chatrooms";
309+ };
310+ restrictRoomCreation = mkOption {
311+ type = types.enum [
312+ true
313+ false
314+ "admin"
315+ "local"
316+ ];
317+ default = false;
318+ description = "Restrict room creation to server admins";
319+ };
320+ maxHistoryMessages = mkOption {
321+ type = types.int;
322+ default = 20;
323+ description = "Specifies a limit on what each room can be configured to keep";
324+ };
325+ roomLocking = mkOption {
326+ type = types.bool;
327+ default = true;
328+ description = ''
329+ Enables room locking, which means that a room must be
330+ configured before it can be used. Locked rooms are invisible
331+ and cannot be entered by anyone but the creator
332+ '';
333+ };
334+ roomLockTimeout = mkOption {
335+ type = types.int;
336+ default = 300;
337+ description = ''
338+ Timeout after which the room is destroyed or unlocked if not
339+ configured, in seconds
340+ '';
341+ };
342+ tombstones = mkOption {
343+ type = types.bool;
344+ default = true;
345+ description = ''
346+ When a room is destroyed, it leaves behind a tombstone which
347+ prevents the room being entered or recreated. It also allows
348+ anyone who was not in the room at the time it was destroyed
349+ to learn about it, and to update their bookmarks. Tombstones
350+ prevents the case where someone could recreate a previously
351+ semi-anonymous room in order to learn the real JIDs of those
352+ who often join there.
353+ '';
354+ };
355+ tombstoneExpiry = mkOption {
356+ type = types.int;
357+ default = 2678400;
358+ description = ''
359+ This settings controls how long a tombstone is considered
360+ valid. It defaults to 31 days. After this time, the room in
361+ question can be created again.
362+ '';
363+ };
364+ allowners_muc = mkOption {
365+ type = types.bool;
366+ default = false;
367+ description = ''
368+ Add module allowners, any user in chat is able to
369+ kick other. Useful in jitsi-meet to kick ghosts.
370+ '';
371+ };
372+ vcard_muc = mkOption {
373+ type = types.bool;
374+ default = true;
375+ description = "Adds the ability to set vCard for Multi User Chat rooms";
376+ };
00377378+ # Extra parameters. Defaulting to prosody default values.
379+ # Adding them explicitly to make them visible from the options
380+ # documentation.
381+ #
382+ # See https://prosody.im/doc/modules/mod_muc for more details.
383+ roomDefaultPublic = mkOption {
384+ type = types.bool;
385+ default = true;
386+ description = "If set, the MUC rooms will be public by default.";
387+ };
388+ roomDefaultMembersOnly = mkOption {
389+ type = types.bool;
390+ default = false;
391+ description = "If set, the MUC rooms will only be accessible to the members by default.";
392+ };
393+ roomDefaultModerated = mkOption {
394+ type = types.bool;
395+ default = false;
396+ description = "If set, the MUC rooms will be moderated by default.";
397+ };
398+ roomDefaultPublicJids = mkOption {
399+ type = types.bool;
400+ default = false;
401+ description = "If set, the MUC rooms will display the public JIDs by default.";
402+ };
403+ roomDefaultChangeSubject = mkOption {
404+ type = types.bool;
405+ default = false;
406+ description = "If set, the rooms will display the public JIDs by default.";
407+ };
408+ roomDefaultHistoryLength = mkOption {
409+ type = types.int;
410+ default = 20;
411+ description = "Number of history message sent to participants by default.";
412+ };
413+ roomDefaultLanguage = mkOption {
414+ type = types.str;
415+ default = "en";
416+ description = "Default room language.";
417+ };
418+ extraConfig = mkOption {
419+ type = types.lines;
420+ default = "";
421+ description = "Additional MUC specific configuration";
0422 };
423 };
424+ };
425426+ uploadHttpOpts = _: {
427+ options = {
428+ domain = mkOption {
429+ type = types.nullOr types.str;
430+ description = "Domain name for the http-upload service";
431+ };
432+ uploadFileSizeLimit = mkOption {
433+ type = types.str;
434+ default = "50 * 1024 * 1024";
435+ description = "Maximum file size, in bytes. Defaults to 50MB.";
436+ };
437+ uploadExpireAfter = mkOption {
438+ type = types.str;
439+ default = "60 * 60 * 24 * 7";
440+ description = "Max age of a file before it gets deleted, in seconds.";
441+ };
442+ userQuota = mkOption {
443+ type = types.nullOr types.int;
444+ default = null;
445+ example = 1234;
446+ description = ''
447+ Maximum size of all uploaded files per user, in bytes. There
448+ will be no quota if this option is set to null.
449+ '';
450+ };
451+ httpUploadPath = mkOption {
452+ type = types.str;
453+ description = ''
454+ Directory where the uploaded files will be stored when the http_upload module is used.
455+ By default, uploaded files are put in a sub-directory of the default Prosody storage path (usually /var/lib/prosody).
456+ '';
457+ default = "/var/lib/prosody";
000458 };
459 };
460+ };
461462+ httpFileShareOpts = _: {
463+ freeformType =
464+ with types;
465+ let
466+ atom = oneOf [
467+ int
468+ bool
469+ str
470+ (listOf atom)
471+ ];
472+ in
473+ attrsOf (nullOr atom)
474+ // {
475+ description = "int, bool, string or list of them";
000000476 };
477+ options.domain = mkOption {
478+ type = with types; nullOr str;
479+ description = "Domain name for a http_file_share service.";
480 };
481+ };
482483+ vHostOpts = _: {
484+ options = {
485+ # TODO: require attribute
486+ domain = mkOption {
487+ type = types.str;
488+ description = "Domain name";
489+ };
490+491+ enabled = mkOption {
492+ type = types.bool;
493+ default = false;
494+ description = "Whether to enable the virtual host";
495+ };
496+497+ ssl = mkOption {
498+ type = types.nullOr (types.submodule sslOpts);
499+ default = null;
500+ description = "Paths to SSL files";
501+ };
502503+ extraConfig = mkOption {
504+ type = types.lines;
505+ default = "";
506+ description = "Additional virtual host specific configuration";
507+ };
508+ };
509+ };
510511+ configFile =
512+ let
513+ httpDiscoItems =
514+ optional (cfg.uploadHttp != null) {
515+ url = cfg.uploadHttp.domain;
516+ description = "HTTP upload endpoint";
517+ }
518+ ++ optional (cfg.httpFileShare != null) {
519+ url = cfg.httpFileShare.domain;
520+ description = "HTTP file share endpoint";
521 };
522+ mucDiscoItems = builtins.foldl' (
523+ acc: muc:
524+ [
525+ {
526+ url = muc.domain;
527+ description = "${muc.domain} MUC endpoint";
528+ }
529+ ]
530+ ++ acc
531+ ) [ ] cfg.muc;
532+ discoItems = cfg.disco_items ++ httpDiscoItems ++ mucDiscoItems;
533+ in
534+ pkgs.writeText "prosody.cfg.lua" ''
535+ pidfile = "/run/prosody/prosody.pid"
536+537+ log = ${cfg.log}
538+539+ data_path = "${cfg.dataDir}"
540+ plugin_paths = {
541+ ${lib.concatStringsSep ", " (map (n: "\"${n}\"") cfg.extraPluginPaths)}
542+ }
543544+ ${optionalString (cfg.ssl != null) (createSSLOptsStr cfg.ssl)}
0000545546+ admins = ${toLua cfg.admins}
0000547548+ modules_enabled = {
0000549550+ ${lib.concatStringsSep "\n " (
551+ lib.mapAttrsToList (name: val: optionalString val "${toLua name};") cfg.modules
552+ )}
553+ ${lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.package.communityModules)}
554+ ${lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.extraModules)}
555 };
556557+ disco_items = {
558+ ${lib.concatStringsSep "\n" (builtins.map (x: ''{ "${x.url}", "${x.description}"};'') discoItems)}
559+ };
560561+ allow_registration = ${toLua cfg.allowRegistration}
562563+ c2s_require_encryption = ${toLua cfg.c2sRequireEncryption}
564565+ s2s_require_encryption = ${toLua cfg.s2sRequireEncryption}
566+ s2s_secure_auth = ${toLua cfg.s2sSecureAuth}
567+ s2s_insecure_domains = ${toLua cfg.s2sInsecureDomains}
568+ s2s_secure_domains = ${toLua cfg.s2sSecureDomains}
569570+ authentication = ${toLua cfg.authentication}
571+572+ http_interfaces = ${toLua cfg.httpInterfaces}
573+ https_interfaces = ${toLua cfg.httpsInterfaces}
574+575+ http_ports = ${toLua cfg.httpPorts}
576+ https_ports = ${toLua cfg.httpsPorts}
577578+ ${cfg.extraConfig}
579580+ ${lib.concatMapStrings (muc: ''
581+ Component ${toLua muc.domain} "muc"
582+ modules_enabled = { "muc_mam"; ${optionalString muc.vcard_muc ''"vcard_muc";''} ${optionalString muc.allowners_muc ''"muc_allowners";''} }
583+ name = ${toLua muc.name}
584+ restrict_room_creation = ${toLua muc.restrictRoomCreation}
585+ max_history_messages = ${toLua muc.maxHistoryMessages}
586+ muc_room_locking = ${toLua muc.roomLocking}
587+ muc_room_lock_timeout = ${toLua muc.roomLockTimeout}
588+ muc_tombstones = ${toLua muc.tombstones}
589+ muc_tombstone_expiry = ${toLua muc.tombstoneExpiry}
590+ muc_room_default_public = ${toLua muc.roomDefaultPublic}
591+ muc_room_default_members_only = ${toLua muc.roomDefaultMembersOnly}
592+ muc_room_default_moderated = ${toLua muc.roomDefaultModerated}
593+ muc_room_default_public_jids = ${toLua muc.roomDefaultPublicJids}
594+ muc_room_default_change_subject = ${toLua muc.roomDefaultChangeSubject}
595+ muc_room_default_history_length = ${toLua muc.roomDefaultHistoryLength}
596+ muc_room_default_language = ${toLua muc.roomDefaultLanguage}
597+ ${muc.extraConfig}
598+ '') cfg.muc}
599+600+ ${lib.optionalString (cfg.uploadHttp != null) ''
601+ Component ${toLua cfg.uploadHttp.domain} "http_upload"
602+ http_upload_file_size_limit = ${cfg.uploadHttp.uploadFileSizeLimit}
603+ http_upload_expire_after = ${cfg.uploadHttp.uploadExpireAfter}
604+ ${lib.optionalString (
605+ cfg.uploadHttp.userQuota != null
606+ ) "http_upload_quota = ${toLua cfg.uploadHttp.userQuota}"}
607+ http_upload_path = ${toLua cfg.uploadHttp.httpUploadPath}
608+ ''}
609+610+ ${lib.optionalString (cfg.httpFileShare != null) ''
611+ Component ${toLua cfg.httpFileShare.domain} "http_file_share"
612+ ${settingsToLua " http_file_share_" (cfg.httpFileShare // { domain = null; })}
613+ ''}
614+615+ ${lib.concatStringsSep "\n" (
616+ lib.mapAttrsToList (n: v: ''
617+ VirtualHost "${v.domain}"
618+ enabled = ${boolToString v.enabled};
619+ ${optionalString (v.ssl != null) (createSSLOptsStr v.ssl)}
620+ ${v.extraConfig}
621+ '') cfg.virtualHosts
622+ )}
623+ '';
624+625+in
626+{
627+ options = {
628+ services.prosody = {
629 enable = mkOption {
630 type = types.bool;
631 default = false;
632 description = "Whether to enable the prosody server";
633+ };
634+635+ checkConfig = mkOption {
636+ type = types.bool;
637+ default = true;
638+ example = false;
639+ description = "Check the configuration file with `prosodyctl check config`";
640 };
641642 xmppComplianceSuite = mkOption {
···916 }
917 '';
918 };
0919 };
920 };
92100922 config = mkIf cfg.enable {
0923 assertions =
924 let
925 genericErrMsg = ''
···954955 environment.systemPackages = [ cfg.package ];
956957+ environment.etc."prosody/prosody.cfg.lua".source =
958+ if cfg.checkConfig then
959+ pkgs.runCommandLocal "prosody.cfg.lua-checked"
960+ {
961+ nativeBuildInputs = [ cfg.package ];
0962 }
963+ ''
964+ cp ${configFile} prosody.cfg.lua
965+ prosodyctl --config ./prosody.cfg.lua check config
966+ touch $out
967+ ''
968+ else
969+ configFile;
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000970971 users.users.prosody = mkIf (cfg.user == "prosody") {
972 uid = config.ids.uids.prosody;
···1013 })
1014 ];
1015 };
01016 };
10171018 meta.doc = ./prosody.md;