Prosody: Difference between revisions

Klinger (talk | contribs)
first version with link to manual
 
Tie-ling (talk | contribs)
add detailed config
Line 2: Line 2:


It is documented in the [https://nixos.org/manual/nixos/stable/#module-services-prosody NixOS manual].
It is documented in the [https://nixos.org/manual/nixos/stable/#module-services-prosody NixOS manual].
This page describes how to setup a walled-off Prosody instance for your organisation or family, with STUN/TURN support and http upload.  This setup has server-to-server communication disabled.
= SSL Certificate with ACME =
This article assumes a working [[ACME]] configuration for certificate
renewal.
<syntaxhighlight lang="nix">
{
  config,
  ...
}:
let
  sslCertDir = config.security.acme.certs."example.org".directory;
  domainName = "example.org";
in
{
  # further prosody & coturn configuration goes here
  ...
}
</syntaxhighlight>
= Set up Prosody =
== Open firewall for client to server c2s ==
<syntaxhighlight lang="nix">
  networking.firewall = {
    allowedTCPPorts = [
      # prosody client to server
      5222
      5223
    ];
  };
</syntaxhighlight>
== Authentication and XMPP modules ==
<syntaxhighlight lang="nix">
  services.prosody = {
    # this is a minimal server config with turn and http upload
    # all server to server connection are blocked
    enable = true;
    admins = [ "admin@${domainName}" ];
    allowRegistration = false;
    authentication = "internal_plain";
    s2sSecureAuth = true;
    c2sRequireEncryption = true;
    modules = {
      admin_adhoc = false;
      cloud_notify = false;
      pep = false;
      blocklist = false;
      bookmarks = false;
      dialback = false;
      ping = false;
      private = false;
      register = false;
      vcard_legacy = false;
    };
    xmppComplianceSuite = false;
  };
</syntaxhighlight>
== Setup Multi User Conference module ==
<syntaxhighlight lang="nix">
  services.prosody = {
    muc = [
      {
        domain = "muc.xmpp.${domainName}";
        # only admin can create public channels
        # everyone can create private chat rooms
        restrictRoomCreation = true;
      }
    ];
}
</syntaxhighlight>
== Setup virtual host and ssl ==
<syntaxhighlight lang="nix">
  services.prosody = {
    ssl = {
      cert = "${sslCertDir}/fullchain.pem";
      key = "${sslCertDir}/key.pem";
    };
    virtualHosts = {
      # xmpp server for "@example.org" is hosted on "xmpp.example.org"
      # use SRV records.
      "xmpp.${domainName}" = {
        domain = "${domainName}";
        enabled = true;
      };
    };
  };
</syntaxhighlight>
You also need to set proper file permissions on the cert directory and key files.
See [[ACME#Integration_with_service_modules]].
== Optional: use sqlite ==
<syntaxhighlight lang="nix">
  services.prosody = {
    extraConfig = ''
      storage = "sql"
      sql = {
        driver = "SQLite3";
        database = "prosody.sqlite"; -- The database name to use. For SQLite3 this the database filename (relative to the data storage directory).
      }
    '';
  };
</syntaxhighlight>
sqlite seems to be more performant than the default file-backed
storage driver.
= Set up coturn =
== Open firewall ports ==
<syntaxhighlight lang="nix">
  networking.firewall = {
    allowedTCPPorts = [
      # prosody turn/stun with coturn
      # see /run/coturn/turnserver.cfg
      3478
      3479
      5349
      5350
    ];
    allowedUDPPorts = [
      # prosody turn/stun with coturn
      3478
      3479
      5349
      5350
    ];
    allowedUDPPortRanges = [
      # coturn
      {
        from = 49152;
        to = 65535;
      }
    ];
  };
</syntaxhighlight>
== Set up coturn ==
<syntaxhighlight lang="nix">
  age.secrets.prosody-coturn = {
    file = ./prosody-coturn.age;
    # -rw-r--r--
    mode = "644";
  };
  services.coturn = {
    # https://prosody.im/doc/coturn
    enable = true;
    listening-port = 3478;
    pkey = "${sslCertDir}/key.pem";
    cert = "${sslCertDir}/fullchain.pem";
    realm = "turn.xmpp.${domainName}";
    static-auth-secret-file = config.age.secrets.prosody-coturn.path;
    use-auth-secret = true;
  };
</syntaxhighlight>
== Connect to prosody ==
<syntaxhighlight lang="nix">
  services.prosody.virtualHosts."xmpp.${domainName}".extraConfig = ''
    turn_external_host = "turn.xmpp.${domainName}"
    turn_external_secret = "unfortunately this is a inline password"
  '';
  services.prosody.extraModules = [ "turn_external" ];
</syntaxhighlight>
= http upload with prosody-filer and nginx =
== Open firewall ports ==
<syntaxhighlight lang="nix">
  networking.firewall = {
    allowedTCPPorts = [
      # prosody https upload
      443
    ];
  };
</syntaxhighlight>
== Setup prosody-filer service ==
<syntaxhighlight lang="nix">
  # set up directory for storing uploaded file
  systemd.services.prosody-filer.serviceConfig = {
    StateDirectory = "prosody-filer";
    RuntimeDirectory = "prosody-filer";
    RuntimeDirectoryMode = "0750";
  };
  services.prosody-filer = {
    enable = true;
    settings = {
      secret = "plain in line password";
      storeDir = "/var/lib/prosody-filer/uploads/";
      # this option refers to the upload url
      # https://upload.xmpp.${domainName}/upload/
      #                                  <------->
      # do not change this, else 404
      uploadSubDir = "upload/";
    };
  };
</syntaxhighlight>
== Set up nginx virtual host ==
<syntaxhighlight lang="nix">
  services.nginx = {
    clientMaxBodySize = "50m";
    virtualHosts."upload.xmpp.${domainName}" = {
      forceSSL = true;
      useACMEHost = "${domainName}";
      locations."/upload/" = {
        proxyPass = "http://localhost:5050/upload/";
        # config copied from https://github.com/ThomasLeister/prosody-filer/blob/develop/README.md
        extraConfig = ''
            proxy_request_buffering off;
          if ( $request_method = OPTIONS ) {
                  add_header Access-Control-Allow-Origin '*';
                  add_header Access-Control-Allow-Methods 'PUT, GET, OPTIONS, HEAD';
                  add_header Access-Control-Allow-Headers 'Authorization, Content-Type';
                  add_header Access-Control-Allow-Credentials 'true';
                  add_header Content-Length 0;
                  add_header Content-Type text/plain;
                  return 200;
          }
        '';
      };
    };
  };
</syntaxhighlight>
== Connect filer to Prosody ==
<syntaxhighlight lang="nix">
  services.prosody.extraConfig = ''
    Component "upload.xmpp.${domainName}" "http_upload_external"
    http_upload_external_secret = "should be the same pwd as above";
    http_upload_external_base_url = "https://upload.xmpp.${domainName}/upload/"
    http_upload_external_file_size_limit = 52428800
  '';
  services.prosody.virtualHosts."xmpp.${domainName}".extraConfig = ''
    disco_items = {
      { "upload.${domainName}", "http upload" };
    }
  '';
  # mod_http_upload_external is a community module
  # has to be installed via
  # https://modules.prosody.im/mod_http_upload_external.html#installation
  ## Clone Prosody Community Modules Repo
  # cd /var/lib/prosody
  # hg clone https://hg.prosody.im/prosody-modules/ prosody-modules
  # update plugins via hg pull --update
  services.prosody.extraPluginPaths = [
    "/var/lib/prosody/prosody-modules/mod_http_upload_external"
  ];
</syntaxhighlight>




[[Category:Server]]
[[Category:Server]]
[[Category:NixOS Manual]]
[[Category:NixOS Manual]]