{ pkgs, lib, config, hosts, ... }: let inherit (config.services) prosody; inherit (hosts.mermet.config.services) coturn; domain = config.networking.domain; commas = lib.concatMapStringsSep "," toString; in { imports = [ prosody/biboumi.nix ]; networking.nftables.ruleset = '' table inet filter { chain input-net { tcp dport { xmpp-client, xmpp-server } counter accept comment "prosody: XMPP" tcp dport {${commas (with prosody.settings; c2s_direct_tls_ports ++ s2s_direct_tls_ports)}} counter accept comment "prosody: XMPPS" tcp dport {${commas prosody.settings.proxy65_ports}} counter accept comment "prosody: XMPP XEP-0065 File Transfer Proxy" tcp dport {${commas prosody.settings.https_ports}} counter accept comment "prosody: HTTPS" } chain output-net { skuid ${prosody.user} counter accept comment "prosody" } } ''; /* services.upnpc.redirections = [ { description = "XMPP"; externalPort = 5222; protocol = "TCP"; duration = 30 * 60; service.wantedBy = ["prosody.service"]; service.partOf = ["prosody.service"]; } { description = "XMPP"; externalPort = 5269; protocol = "TCP"; duration = 30 * 60; service.wantedBy = ["prosody.service"]; service.partOf = ["prosody.service"]; } { description = "XMPP-FTP"; externalPort = 5000; protocol = "TCP"; duration = 30 * 60; service.wantedBy = ["prosody.service"]; service.partOf = ["prosody.service"]; } ] ++ map (externalPort: { description = "XMPP-HTTPS"; inherit externalPort; protocol="TCP"; duration = 30 * 60; service.wantedBy = ["prosody.service"]; service.partOf = ["prosody.service"]; }) prosody.settings.https_ports; */ /* services.tor.relay.hiddenServices."${domain}/xmpp".map = with prosody.settings; c2s_direct_tls_ports ++ s2s_direct_tls_ports ++ proxy65_ports ++ https_ports; */ users.groups.acme.members = [ prosody.user ]; security.acme.certs."${domain}" = { postRun = "systemctl try-restart prosody"; }; fileSystems."/var/lib/prosody" = { device = "rpool/var/prosody"; fsType = "zfs"; }; services.sanoid.datasets = { "rpool/var/prosody" = { use_template = [ "snap" ]; daily = 7; }; }; systemd.services.prosody = { wants = [ "acme-selfsigned-${domain}.service" "acme-${domain}.service" ]; after = [ "acme-selfsigned-${domain}.service" ]; }; # sudo -u prosody prosodyctl check services.prosody = { enable = true; xmppComplianceSuite = true; components = { "biboumi.${domain}" = { settings = { component_secret = "useless-secret-on-loopback"; }; }; "proxy65.${domain}" = { #module = "proxy65"; settings = { proxy65_address = "proxy65.${domain}"; proxy65_acl = [ domain ]; }; }; "pubsub.${domain}" = { module = "pubsub"; settings = { modules_enabled = [ #"pubsub_alertmanager" "pubsub_feeds" #"pubsub_github" "pubsub_summary" "pubsub_text_interface" ]; admins = { }; autocreate_on_subscribe = false; autocreate_on_publish = false; pubsub_max_items = 256; pubsub_summary_templates = { "http://www.w3.org/2005/Atom" = "{summary|or{{author/name|and{{author/name} posted }}{title}}}"; }; }; }; "salons.${domain}" = { module = "muc"; settings = { modules_enabled = [ "http_muc_log" "muc_mam" "vcard_muc" #"muc_log" #"muc_log_http" ]; name = "Prosody Chatrooms"; restrict_room_creation = "local"; max_history_messages = 42; muc_room_locking = true; muc_room_lock_timeout = 600; muc_tombstones = true; muc_tombstone_expiry = 31 * 24 * 60 * 60; muc_room_default_public = true; muc_room_default_members_only = false; muc_room_default_moderated = true; muc_room_default_public_jids = false; muc_room_default_change_subject = true; muc_room_default_history_length = 42; muc_room_default_language = "fr"; # mod_muc_mam muc_log_by_default = true; muc_log_presences = false; log_all_rooms = false; muc_log_expires_after = "1w"; muc_log_cleanup_interval = 4 * 60 * 60; # mod_http_muc_log http_muc_log_show_images = true; #http_muc_log_default_view = "latest"; http_muc_log_list_order = [ "test@salons.${domain}" ]; }; }; "tmp.${domain}" = { module = "http_file_share"; settings = { size_limit = 100 * 1024 * 1024; # 100 MiB daily_quota = 200 * 1024 * 1024; # 200 MiB per day per user global_quota = 1 * 1024 * 1024 * 1024; # 1 GiB total expires_after = 7 * 24 * 60 * 60; # 7 days }; }; }; virtualHosts.${domain} = { useACMEHost = domain; settings = { enabled = true; }; }; settings = { admins = [ "julm@${domain}" ]; site_name = "soucephile.fr"; contact_info = { #abuse = [ "mailto:abuse@${domain}", "xmpp:abuse@${domain}" ]; #admin = [ "mailto:admin@${domain}", "xmpp:admin@${domain}" ]; #feedback = [ "http://${domain}/feedback.php", "mailto:feedback@${domain}", "xmpp:feedback@${domain}" ]; #sales = [ "xmpp:bard@${domain}" ]; #security = [ "xmpp:security@${domain}" ]; #support = [ "http://${domain}/support.php", "xmpp:support@${domain}" ]; }; allow_registration = true; registration_invite_only = true; authentication = "internal_hashed"; # Listen only in IPv4 until hosting provider's IPv6 works well. interfaces = [ "0.0.0.0" ]; c2s_interfaces = [ "0.0.0.0" ]; c2s_ports = [ 5222 ]; c2s_direct_tls_ports = [ 5223 ]; c2s_direct_tls_ssl = { key = "/var/lib/acme/${domain}/key.pem"; certificate = "/var/lib/acme/${domain}/fullchain.pem"; }; c2s_require_encryption = true; s2s_require_encryption = true; s2s_secure_auth = true; s2s_ports = [ 5269 ]; s2s_direct_tls_ports = [ 5270 ]; s2s_direct_tls_ssl = { key = "/var/lib/acme/${domain}/key.pem"; certificate = "/var/lib/acme/${domain}/fullchain.pem"; }; ssl.key = "/var/lib/acme/${domain}/key.pem"; ssl.certificate = "/var/lib/acme/${domain}/fullchain.pem"; http_ports = [ ]; https_ports = [ 5281 ]; proxy65_ports = [ 5000 ]; disco_items = [ [ "biboumi.${domain}" "Gateway to IRC (Internet Relay Chat) servers" ] ]; log = { # debug = "*syslog"; info = "*syslog"; warn = "*syslog"; error = "*syslog"; }; storage = { archive = "xmlarchive"; muc_log = "xmlarchive"; }; # mod_mam archive_expires_after = "3m"; # months archive_cleanup_interval = 4 * 60 * 60; default_archive_policy = "roster"; limits = { c2s = { rate = "3kb/s"; burst = "2s"; }; s2sin = { rate = "10kb/s"; burst = "5s"; }; }; csi_important_payloads = { # Anything in this namespace: #"{urn:example:important-namespace}" # Specific element name and namespace: #"{urn:example:xmpp:priority}super-important" }; feeds = { code_gouv_fr = "https://code.gouv.fr/feed/feed.xml"; haskellweekly = "https://haskellweekly.news/newsletter.atom"; planet_jabber = "https://planet.jabber.org/atom.xml"; #prosody_blog = "http://blog.prosody.im/feed/atom.xml"; }; modules_enabled = [ "admin_shell" "announce" "blocklist" #"cloud_notify_encrypted" "csi_simple" #"extdisco" "groups" "invites" "invites_page" "invites_register" "limits" "motd" #"net_multiplex" "register_apps" "server_contact_info" #"throttle_presence" "turn_external" "vcard4" "watchregistrations" "welcome" "storage_xmlarchive" ]; modules_disabled = [ "cloud_notify" # not encrypted even with OMEMO "http_files" "http_upload" #"proxy65" "vcard_legacy" "websocket" ]; smacks_enabled_s2s = true; smacks_s2s_resend = true; turn_external_secret = coturn.static-auth-secret; #turn_external_secret = "ENV_TURN_EXTERNAL_SECRET"; turn_external_host = "turn.${domain}"; turn_external_port = 3478; turn_external_ttl = 86400; # http_files_dir = "/var/lib/prosody/files" # http_external_url = "https://tmp.${domain}:5281" # https_certificate = "/var/lib/acme/${domain}/fullchain.pem" # https_key = "/var/lib/acme/${domain}/key.pem" # certificates = "/var/lib/acme" #ports = {80}; #ssl_ports = {443}; }; package = pkgs.prosody.override { withCommunityModules = [ "http_muc_log" #"log_auth" #"offline_email" #"pubsub_alertmanager" "pubsub_feeds" #"pubsub_github" "pubsub_summary" "pubsub_text_interface" "register_apps" "invites_page" #"extdisco" "storage_xmlarchive" ]; }; }; }