diff options
Diffstat (limited to 'nixos/modules/services/web-apps/discourse.xml')
-rw-r--r-- | nixos/modules/services/web-apps/discourse.xml | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/nixos/modules/services/web-apps/discourse.xml b/nixos/modules/services/web-apps/discourse.xml new file mode 100644 index 00000000000..ad9b65abf51 --- /dev/null +++ b/nixos/modules/services/web-apps/discourse.xml @@ -0,0 +1,355 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="module-services-discourse"> + <title>Discourse</title> + <para> + <link xlink:href="https://www.discourse.org/">Discourse</link> is a + modern and open source discussion platform. + </para> + + <section xml:id="module-services-discourse-basic-usage"> + <title>Basic usage</title> + <para> + A minimal configuration using Let's Encrypt for TLS certificates looks like this: +<programlisting> +services.discourse = { + <link linkend="opt-services.discourse.enable">enable</link> = true; + <link linkend="opt-services.discourse.hostname">hostname</link> = "discourse.example.com"; + admin = { + <link linkend="opt-services.discourse.admin.email">email</link> = "admin@example.com"; + <link linkend="opt-services.discourse.admin.username">username</link> = "admin"; + <link linkend="opt-services.discourse.admin.fullName">fullName</link> = "Administrator"; + <link linkend="opt-services.discourse.admin.passwordFile">passwordFile</link> = "/path/to/password_file"; + }; + <link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file"; +}; +<link linkend="opt-security.acme.defaults.email">security.acme.email</link> = "me@example.com"; +<link linkend="opt-security.acme.acceptTerms">security.acme.acceptTerms</link> = true; +</programlisting> + </para> + + <para> + Provided a proper DNS setup, you'll be able to connect to the + instance at <literal>discourse.example.com</literal> and log in + using the credentials provided in + <literal>services.discourse.admin</literal>. + </para> + </section> + + <section xml:id="module-services-discourse-tls"> + <title>Using a regular TLS certificate</title> + <para> + To set up TLS using a regular certificate and key on file, use + the <xref linkend="opt-services.discourse.sslCertificate" /> + and <xref linkend="opt-services.discourse.sslCertificateKey" /> + options: + +<programlisting> +services.discourse = { + <link linkend="opt-services.discourse.enable">enable</link> = true; + <link linkend="opt-services.discourse.hostname">hostname</link> = "discourse.example.com"; + <link linkend="opt-services.discourse.sslCertificate">sslCertificate</link> = "/path/to/ssl_certificate"; + <link linkend="opt-services.discourse.sslCertificateKey">sslCertificateKey</link> = "/path/to/ssl_certificate_key"; + admin = { + <link linkend="opt-services.discourse.admin.email">email</link> = "admin@example.com"; + <link linkend="opt-services.discourse.admin.username">username</link> = "admin"; + <link linkend="opt-services.discourse.admin.fullName">fullName</link> = "Administrator"; + <link linkend="opt-services.discourse.admin.passwordFile">passwordFile</link> = "/path/to/password_file"; + }; + <link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file"; +}; +</programlisting> + + </para> + </section> + + <section xml:id="module-services-discourse-database"> + <title>Database access</title> + <para> + <productname>Discourse</productname> uses + <productname>PostgreSQL</productname> to store most of its + data. A database will automatically be enabled and a database + and role created unless <xref + linkend="opt-services.discourse.database.host" /> is changed from + its default of <literal>null</literal> or <xref + linkend="opt-services.discourse.database.createLocally" /> is set + to <literal>false</literal>. + </para> + + <para> + External database access can also be configured by setting + <xref linkend="opt-services.discourse.database.host" />, <xref + linkend="opt-services.discourse.database.username" /> and <xref + linkend="opt-services.discourse.database.passwordFile" /> as + appropriate. Note that you need to manually create a database + called <literal>discourse</literal> (or the name you chose in + <xref linkend="opt-services.discourse.database.name" />) and + allow the configured database user full access to it. + </para> + </section> + + <section xml:id="module-services-discourse-mail"> + <title>Email</title> + <para> + In addition to the basic setup, you'll want to configure an SMTP + server <productname>Discourse</productname> can use to send user + registration and password reset emails, among others. You can + also optionally let <productname>Discourse</productname> receive + email, which enables people to reply to threads and conversations + via email. + </para> + + <para> + A basic setup which assumes you want to use your configured <link + linkend="opt-services.discourse.hostname">hostname</link> as + email domain can be done like this: + +<programlisting> +services.discourse = { + <link linkend="opt-services.discourse.enable">enable</link> = true; + <link linkend="opt-services.discourse.hostname">hostname</link> = "discourse.example.com"; + <link linkend="opt-services.discourse.sslCertificate">sslCertificate</link> = "/path/to/ssl_certificate"; + <link linkend="opt-services.discourse.sslCertificateKey">sslCertificateKey</link> = "/path/to/ssl_certificate_key"; + admin = { + <link linkend="opt-services.discourse.admin.email">email</link> = "admin@example.com"; + <link linkend="opt-services.discourse.admin.username">username</link> = "admin"; + <link linkend="opt-services.discourse.admin.fullName">fullName</link> = "Administrator"; + <link linkend="opt-services.discourse.admin.passwordFile">passwordFile</link> = "/path/to/password_file"; + }; + mail.outgoing = { + <link linkend="opt-services.discourse.mail.outgoing.serverAddress">serverAddress</link> = "smtp.emailprovider.com"; + <link linkend="opt-services.discourse.mail.outgoing.port">port</link> = 587; + <link linkend="opt-services.discourse.mail.outgoing.username">username</link> = "user@emailprovider.com"; + <link linkend="opt-services.discourse.mail.outgoing.passwordFile">passwordFile</link> = "/path/to/smtp_password_file"; + }; + <link linkend="opt-services.discourse.mail.incoming.enable">mail.incoming.enable</link> = true; + <link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file"; +}; +</programlisting> + + This assumes you have set up an MX record for the address you've + set in <link linkend="opt-services.discourse.hostname">hostname</link> and + requires proper SPF, DKIM and DMARC configuration to be done for + the domain you're sending from, in order for email to be reliably delivered. + </para> + + <para> + If you want to use a different domain for your outgoing email + (for example <literal>example.com</literal> instead of + <literal>discourse.example.com</literal>) you should set + <xref linkend="opt-services.discourse.mail.notificationEmailAddress" /> and + <xref linkend="opt-services.discourse.mail.contactEmailAddress" /> manually. + </para> + + <note> + <para> + Setup of TLS for incoming email is currently only configured + automatically when a regular TLS certificate is used, i.e. when + <xref linkend="opt-services.discourse.sslCertificate" /> and + <xref linkend="opt-services.discourse.sslCertificateKey" /> are + set. + </para> + </note> + + </section> + + <section xml:id="module-services-discourse-settings"> + <title>Additional settings</title> + <para> + Additional site settings and backend settings, for which no + explicit <productname>NixOS</productname> options are provided, + can be set in <xref linkend="opt-services.discourse.siteSettings" /> and + <xref linkend="opt-services.discourse.backendSettings" /> respectively. + </para> + + <section xml:id="module-services-discourse-site-settings"> + <title>Site settings</title> + <para> + <quote>Site settings</quote> are the settings that can be + changed through the <productname>Discourse</productname> + UI. Their <emphasis>default</emphasis> values can be set using + <xref linkend="opt-services.discourse.siteSettings" />. + </para> + + <para> + Settings are expressed as a Nix attribute set which matches the + structure of the configuration in + <link xlink:href="https://github.com/discourse/discourse/blob/master/config/site_settings.yml">config/site_settings.yml</link>. + To find a setting's path, you only need to care about the first + two levels; i.e. its category (e.g. <literal>login</literal>) + and name (e.g. <literal>invite_only</literal>). + </para> + + <para> + Settings containing secret data should be set to an attribute + set containing the attribute <literal>_secret</literal> - a + string pointing to a file containing the value the option + should be set to. See the example. + </para> + </section> + + <section xml:id="module-services-discourse-backend-settings"> + <title>Backend settings</title> + <para> + Settings are expressed as a Nix attribute set which matches the + structure of the configuration in + <link xlink:href="https://github.com/discourse/discourse/blob/stable/config/discourse_defaults.conf">config/discourse.conf</link>. + Empty parameters can be defined by setting them to + <literal>null</literal>. + </para> + </section> + + <section xml:id="module-services-discourse-settings-example"> + <title>Example</title> + <para> + The following example sets the title and description of the + <productname>Discourse</productname> instance and enables + <productname>GitHub</productname> login in the site settings, + and changes a few request limits in the backend settings: +<programlisting> +services.discourse = { + <link linkend="opt-services.discourse.enable">enable</link> = true; + <link linkend="opt-services.discourse.hostname">hostname</link> = "discourse.example.com"; + <link linkend="opt-services.discourse.sslCertificate">sslCertificate</link> = "/path/to/ssl_certificate"; + <link linkend="opt-services.discourse.sslCertificateKey">sslCertificateKey</link> = "/path/to/ssl_certificate_key"; + admin = { + <link linkend="opt-services.discourse.admin.email">email</link> = "admin@example.com"; + <link linkend="opt-services.discourse.admin.username">username</link> = "admin"; + <link linkend="opt-services.discourse.admin.fullName">fullName</link> = "Administrator"; + <link linkend="opt-services.discourse.admin.passwordFile">passwordFile</link> = "/path/to/password_file"; + }; + mail.outgoing = { + <link linkend="opt-services.discourse.mail.outgoing.serverAddress">serverAddress</link> = "smtp.emailprovider.com"; + <link linkend="opt-services.discourse.mail.outgoing.port">port</link> = 587; + <link linkend="opt-services.discourse.mail.outgoing.username">username</link> = "user@emailprovider.com"; + <link linkend="opt-services.discourse.mail.outgoing.passwordFile">passwordFile</link> = "/path/to/smtp_password_file"; + }; + <link linkend="opt-services.discourse.mail.incoming.enable">mail.incoming.enable</link> = true; + <link linkend="opt-services.discourse.siteSettings">siteSettings</link> = { + required = { + title = "My Cats"; + site_description = "Discuss My Cats (and be nice plz)"; + }; + login = { + enable_github_logins = true; + github_client_id = "a2f6dfe838cb3206ce20"; + github_client_secret._secret = /run/keys/discourse_github_client_secret; + }; + }; + <link linkend="opt-services.discourse.backendSettings">backendSettings</link> = { + max_reqs_per_ip_per_minute = 300; + max_reqs_per_ip_per_10_seconds = 60; + max_asset_reqs_per_ip_per_10_seconds = 250; + max_reqs_per_ip_mode = "warn+block"; + }; + <link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file"; +}; +</programlisting> + </para> + <para> + In the resulting site settings file, the + <literal>login.github_client_secret</literal> key will be set + to the contents of the + <filename>/run/keys/discourse_github_client_secret</filename> + file. + </para> + </section> + </section> + <section xml:id="module-services-discourse-plugins"> + <title>Plugins</title> + <para> + You can install <productname>Discourse</productname> plugins + using the <xref linkend="opt-services.discourse.plugins" /> + option. Pre-packaged plugins are provided in + <literal><your_discourse_package_here>.plugins</literal>. If + you want the full suite of plugins provided through + <literal>nixpkgs</literal>, you can also set the <xref + linkend="opt-services.discourse.package" /> option to + <literal>pkgs.discourseAllPlugins</literal>. + </para> + + <para> + Plugins can be built with the + <literal><your_discourse_package_here>.mkDiscoursePlugin</literal> + function. Normally, it should suffice to provide a + <literal>name</literal> and <literal>src</literal> attribute. If + the plugin has Ruby dependencies, however, they need to be + packaged in accordance with the <link + xlink:href="https://nixos.org/manual/nixpkgs/stable/#developing-with-ruby">Developing + with Ruby</link> section of the Nixpkgs manual and the + appropriate gem options set in <literal>bundlerEnvArgs</literal> + (normally <literal>gemdir</literal> is sufficient). A plugin's + Ruby dependencies are listed in its + <filename>plugin.rb</filename> file as function calls to + <literal>gem</literal>. To construct the corresponding + <filename>Gemfile</filename> manually, run <command>bundle + init</command>, then add the <literal>gem</literal> lines to it + verbatim. + </para> + + <para> + Much of the packaging can be done automatically by the + <filename>nixpkgs/pkgs/servers/web-apps/discourse/update.py</filename> + script - just add the plugin to the <literal>plugins</literal> + list in the <function>update_plugins</function> function and run + the script: + <programlisting language="bash"> +./update.py update-plugins +</programlisting> + </para> + + <para> + Some plugins provide <link + linkend="module-services-discourse-site-settings">site + settings</link>. Their defaults can be configured using <xref + linkend="opt-services.discourse.siteSettings" />, just like + regular site settings. To find the names of these settings, look + in the <literal>config/settings.yml</literal> file of the plugin + repo. + </para> + + <para> + For example, to add the <link + xlink:href="https://github.com/discourse/discourse-spoiler-alert">discourse-spoiler-alert</link> + and <link + xlink:href="https://github.com/discourse/discourse-solved">discourse-solved</link> + plugins, and disable <literal>discourse-spoiler-alert</literal> + by default: + +<programlisting> +services.discourse = { + <link linkend="opt-services.discourse.enable">enable</link> = true; + <link linkend="opt-services.discourse.hostname">hostname</link> = "discourse.example.com"; + <link linkend="opt-services.discourse.sslCertificate">sslCertificate</link> = "/path/to/ssl_certificate"; + <link linkend="opt-services.discourse.sslCertificateKey">sslCertificateKey</link> = "/path/to/ssl_certificate_key"; + admin = { + <link linkend="opt-services.discourse.admin.email">email</link> = "admin@example.com"; + <link linkend="opt-services.discourse.admin.username">username</link> = "admin"; + <link linkend="opt-services.discourse.admin.fullName">fullName</link> = "Administrator"; + <link linkend="opt-services.discourse.admin.passwordFile">passwordFile</link> = "/path/to/password_file"; + }; + mail.outgoing = { + <link linkend="opt-services.discourse.mail.outgoing.serverAddress">serverAddress</link> = "smtp.emailprovider.com"; + <link linkend="opt-services.discourse.mail.outgoing.port">port</link> = 587; + <link linkend="opt-services.discourse.mail.outgoing.username">username</link> = "user@emailprovider.com"; + <link linkend="opt-services.discourse.mail.outgoing.passwordFile">passwordFile</link> = "/path/to/smtp_password_file"; + }; + <link linkend="opt-services.discourse.mail.incoming.enable">mail.incoming.enable</link> = true; + <link linkend="opt-services.discourse.mail.incoming.enable">plugins</link> = with config.services.discourse.package.plugins; [ + discourse-spoiler-alert + discourse-solved + ]; + <link linkend="opt-services.discourse.siteSettings">siteSettings</link> = { + plugins = { + spoiler_enabled = false; + }; + }; + <link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file"; +}; +</programlisting> + + </para> + </section> +</chapter> |