f8096460bd
Let the update.py script handle the initial, repetitive task of packaging new plugins. With this in place, the plugin only needs to be added to the list in `update-plugins` and most of the work will be done automatically when the script is run. Metadata still needs to be filled in manually and some packages may of course require additional work/patching.
355 lines
16 KiB
XML
355 lines
16 KiB
XML
<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.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>
|