Discourse

From Open Source Ecology
Jump to: navigation, search

Useful Commands

This section will describe useful commands when working with Discourse

# get a shell on the Discourse's docker container
/var/discourse/launcher enter app

# access the rails console (exec from inside the docker container)
rails c

# restart a process from within the docker container (ie: cron, nginx, postgres, redis, rsyslog, unicorn)
sv stop nginx && sv start nginx

Troubleshooting

This section will provide tips on how to troubleshoot the Discourse install

Important Files & Directories

For more information about our Discourse configuration, please see the following files & directories on the Docker Host:

/var/discourse/
/var/discourse/shared/standalone/log/rails/production.log
/var/discourse/shared/standalone/log/rails/unicorn.stderr.log
/var/discourse/shared/standalone/log/var-log/redis/current
/var/discourse/shared/standalone/log/var-log/nginx/{access.log,error.log}
/var/discourse/shared/standalone/log/var-log/postgres/current

And the following files & directories on the Docker Container:

/var/www/discourse/
/var/www/discourse/public
/etc/nginx/conf.d/discourse.conf

2019-11 Install Guide

In 2019-11, I (Michael Altfield) tested an install of Discourse on the OSE Staging Server. I documented the install steps here so they could be exactly reproduced on production

Install Prereqs

First we have to install docker. The version in the yum repos (1.13.1) was too old to be supported by Discourse (which states it requires a minimum of 17.03.1).

Note that the install procedure recommended by Docker and Discourse for Docker is a curl piped to shell. This should never, ever, ever be done. The safe procedure is to manually add the gpg key and repo to the server as get.docker.org script should do -- assuming it were not modified in transit. Note that Docker does *not* cryptographically sign their install script in any way, and it therefore cannot be safely validated.

The gpg key itself is available at the following URL from docker.com

* https://download.docker.com/linux/centos/gpg

Please do your due diligence to validate that this gpg key is the official key and was not manipulated in-transit by Mallory. Unfortunately, at the time of writing, this is non-trivial since there's no signatures on the key, the key is not uploaded to any public keyservers, the docker team doesn't have a keybase account, etc. I submitted a feature request to the docker team's 'for-linux' repo asking them to at least upload this gpg key to the keys.openpgp.org keyserver on 2019-11-12 [1]

# first, install the (ASCII-armored) docker gpg key to /etc/pki/rpm-gpg/docker.gpg
cp docker.gpg /etc/pki/rpm-gpg/docker.gpg
chown root:root /etc/pki/rpm-gpg/docker.gpg
chmod 0644 /etc/pki/rpm-gpg/docker.gpg

# and install the repo
cat << EOF > /etc/yum.repos.d/docker-ce.repo 
[docker-ce-stable]
name=Docker CE Stable - $basearch
baseurl=https://download.docker.com/linux/centos/7/$basearch/stable
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/docker.gpg
EOF

# finally, install docker from the repos
yum install docker-ce

We don't want docker to break our iptables rules. In fact, we don't want our docker container to be able to have Internet access at all; just creating a unix socket file that our host OS's nginx vhost can proxy connections to is sufficient.

sed --in-place=.`date "+%Y%m%d_%H%M%S"` '/iptables/! s%^[^#]*ExecStart=\(.*\)%#ExecStart=\1\nExecStart=\1 --iptables=false%' /usr/lib/systemd/system/docker.service
systemctl daemon-reload

Now we make docker start on system boot & start it up.

systemctl enable docker.service
systemctl start docker.service

Install Discourse

In this step we will configure & install the Discourse docker container and all its components

Clone Repo

From the Disourse Install Guide, checkout the github repo as root to /var/discourse. You'll want to validate that this wasn't modified in transit; there are no cryptographic signatures to validate authenticity of the repo's contents here. A huge failing on Discourse's part (but, again, Discourse's sec is rotten from its foundation in Docker; see above).

sudo -s
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse

The default name of the Discourse docker container is 'app'. Let's rename that to 'discourse_ose'.

mv containers/app.yml containers/discorse_ose.yml

SMTP

The Discourse install script doesn't support the very simple config of an smtp server running on localhost:25 without auth. That is to say, Discourse doesn't support the default postfix config for RHEL/CentOS and most web servers on the net..

We have to manually edit the /var/discourse/containers/app.yml. I couldn't find any Discourse documentation for these DISCOURSE_SMTP_* variables, but I did have success with these values:

Note that 'localhost' resolves to the IP Address of the container created by docker when referenced from within the context of Discourse, but our smtp server is running on the host server. Therefore, we cannot use 'localhost' for the DISCOURSE_SMTP_ADDRESS. Instead, we use the IP Address of the host server's docker0 interface. In this case, it's 172.17.0.1, and that can be verified via the output of `ip address show dev docker0` run on the host where docker is installed (in this case, osestaging1).

TODO: change the name of the Discourse docker app from 'app' to something more sane, such as 'discourse_ose'

TODO: make these sed commands to update the 'container/discourse_ose.yml' file in an automated, robust, and idempotent manner

  DISCOURSE_SMTP_ADDRESS: 172.17.0.1 # this is the IP Address of the host server on the docker0 interface
  DISCOURSE_SMTP_PORT: 25
  DISCOURSE_SMTP_AUTHENTICATION: none
  DISCOURSE_SMTP_OPENSSL_VERIFY_MODE: none
  DISCOURSE_SMTP_ENABLE_START_TLS: false

Also note that I had to update the postfix configuration (/etc/postfix/main.cf) to bind on the docker0 interface, change the `mynetworks_style`, and add the docker0 subnet to the 'mynetworks' list to auth the Discourse docker client to be able to send mail through the smtp server.

root@osestaging1 discourse]# grep -E 'mynetworks|interfaces' /etc/postfix/main.cf
# The inet_interfaces parameter specifies the network interface
# the software claims all active interfaces on the machine. The
# See also the proxy_interfaces parameter, for network addresses that
#inet_interfaces = all
#inet_interfaces = $myhostname
#inet_interfaces = $myhostname, localhost
#inet_interfaces = localhost
inet_interfaces = 127.0.0.1, 172.17.0.1
# The proxy_interfaces parameter specifies the network interface
# the address list specified with the inet_interfaces parameter.
#proxy_interfaces =
#proxy_interfaces = 1.2.3.4
# receives mail on (see the inet_interfaces parameter).
# to $mydestination, $inet_interfaces or $proxy_interfaces.
# ${proxy,inet}_interfaces, while $local_recipient_maps is non-empty
# The mynetworks parameter specifies the list of "trusted" SMTP
# By default (mynetworks_style = subnet), Postfix "trusts" SMTP
# On Linux, this does works correctly only with interfaces specified
# Specify "mynetworks_style = class" when Postfix should "trust" SMTP
# mynetworks list by hand, as described below.
# Specify "mynetworks_style = host" when Postfix should "trust"
#mynetworks_style = class
#mynetworks_style = subnet
#mynetworks_style = host
# Alternatively, you can specify the mynetworks list by hand, in
# which case Postfix ignores the mynetworks_style setting.
#mynetworks = 168.100.189.0/28, 127.0.0.0/8
#mynetworks = $config_directory/mynetworks
#mynetworks = hash:/etc/postfix/network_table
mynetworks = 127.0.0.0/8, 172.17.0.0/16
# - from "trusted" clients (IP address matches $mynetworks) to any destination,
# - destinations that match $inet_interfaces or $proxy_interfaces,
# unknown@[$inet_interfaces] or unknown@[$proxy_interfaces] is returned
[root@osestaging1 discourse]# 


TODO: how to resolve the errors (bug?) that the username & password is not defined on first install? Try just running `./launcher bootstrap` instead of the `docker-setup` script that will fail.

Nginx socket

Also, we already have nginx bound to port 443 as our ssl terminator, so the defaults in app.yml will fail. Instead, we add the 'web.socketed.template.yml' file, remove the 'expose' block, and we'll setup nginx to proxy connections to the resulting discourse unix socket file [2]

Add this line to the "templates" block in /var/discourse/containers/app.yml.

  - "templates/web.socketed.template.yml"

And also comment-out the entire "expose" block and all its contents

#expose:
#  - "80:80"   # http
#  - "443:443" # https

TODO: try the 'discourse-setup' script now

Nginx mod_security

In our other sites hosted on this server, we have a nginx -> varnish -> apache architecture. While I'd like to mimic this architecture for all our sites, it's important to note a few things about Apache, Nginx, mod_security, and Discourse that elucidate why we shouldn't do that.

  1. There's a package in the yum repos for adding mod_security to apache. There is no package for adding mod_security to Nginx. Adding mod_security to Nginx requires compiling Nginx from source
  2. Discourse is heavily tied to Nginx. It appears that nobody has ever run Discourse on Apache, and doing so would be non-trivial. Moreover, our custom Apache vhost config would likely break in future versions of Discourse [3]
  3. Putting apache as a reverse proxy in-front of Discourse could add a significant performance issues because of the way Apache handles long polling, which the Discourse message bus uses [4] [5] [6]
  4. The Discourse install process already compiles Nginx from source so that it can add the brotli module to nginx [7]

Therefore, I think it makes sense to cut apache out of the architecture for our Discourse install entirely. If we're already forced to compile nginx from source, we might as well just update their install-nginx script and configure mod_security in nginx instead of apache. Then our architecture becomes nginx -> varnish -> nginx.

First, let's update the install-nginx script with the logic for installing the depends on our docker container and compiling nginx with mod_security

cd /var/discourse/image/base
cp install-nginx install-nginx.`date "+%Y%m%d_%H%M%S"`.orig

# add a block to checkout the the modsecurity nginx module just before downloading the nginx source
grep 'ModSecurity' install-nginx || sed -i 's%\(curl.*nginx\.org/download.*\)%# mod_security --maltfield\napt-get install -y libmodsecurity-dev modsecurity-crs\ncd /tmp\ngit clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git\n\n\1%' install-nginx

# update the configure line to include the ModSecurity module checked-out above
sed -i '/ModSecurity/! s%^[^#]*./configure \(.*nginx.*\)%#./configure \1\n./configure \1 --add-module=/tmp/ModSecurity-nginx%' install-nginx

# add a line to cleanup section
grep 'rm -fr /tmp/ModSecurity-nginx' install-nginx || sed -i 's%\(rm -fr.*/tmp/nginx.*\)%rm -fr /tmp/ModSecurity-nginx\n\1%' install-nginx

The above commands were carefully crafted to be idempotent and robust so that they will still work on future versions of the install-nginx script, but it's possible that they will break in the future. For reference, here is the resulting file.

Please go ahead and verify that, after running the above commands, your install-nginx file looks sane compared to this one

[root@osestaging1 base]# cat install-nginx
#!/bin/bash
set -e
VERSION=1.17.4
cd /tmp

apt install -y autoconf  


git clone https://github.com/bagder/libbrotli
cd libbrotli
./autogen.sh
./configure
make install

cd /tmp


# this is the reason we are compiling by hand...
git clone https://github.com/google/ngx_brotli.git

# mod_security --maltfield
apt-get install -y libmodsecurity-dev modsecurity-crs
cd /tmp
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git

curl -O https://nginx.org/download/nginx-$VERSION.tar.gz
tar zxf nginx-$VERSION.tar.gz
cd nginx-$VERSION

# so we get nginx user and so on
apt install -y nginx libpcre3 libpcre3-dev zlib1g zlib1g-dev
# we don't want to accidentally upgrade nginx and undo our work
apt-mark hold nginx

# now ngx_brotli has brotli as a submodule
cd /tmp/ngx_brotli && git submodule update --init && cd /tmp/nginx-$VERSION

# ignoring depracations with -Wno-deprecated-declarations while we wait for this https://github.com/google/ngx_brotli/issues/39#issuecomment-254093378
#./configure --with-cc-opt='-g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -Wno-deprecated-declarations' --with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_v2_module --with-http_sub_module --with-stream --with-stream_ssl_module --with-mail --with-mail_ssl_module --with-threads --add-module=/tmp/ngx_brotli
./configure --with-cc-opt='-g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -Wno-deprecated-declarations' --with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_v2_module --with-http_sub_module --with-stream --with-stream_ssl_module --with-mail --with-mail_ssl_module --with-threads --add-module=/tmp/ngx_brotli --add-module=/tmp/ModSecurity-nginx

make install

mv /usr/share/nginx/sbin/nginx /usr/sbin

cd /
rm -fr /tmp/ModSecurity-nginx
rm -fr /tmp/nginx
rm -fr /tmp/libbrotli
rm -fr /tmp/ngx_brotli
rm -fr /etc/nginx/modules-enabled/*
[root@osestaging1 base]#     

Though unintuitive, Discourse's launcher rebuild script won't actually use these local files in image/base/*, including the install-nginx script modified above. To make sure that our Discourse docker container users a docker image with the nginx changes made above, we have to explicitly specify the image in the hard-coded image variable of the launcher script. This, sadly, is not documented anywhere by the Discourse project, and I only discovered this solution after much trial-and-error.

cd /var/discourse

# replace the line "image="discourse/base:<version>" with 'image="discourse_ose"'
grep 'discourse_ose' launcher || sed --in-place=.`date "+%Y%m%d_%H%M%S"` '/base_image/! s%^\(\s*\)image=\(.*\)$%#\1image=\2\n\1image="discourse_ose"%' launcher

And now we must build the 'discourse_ose' docker image, which will execute the updated install-nginx script and then become available to the launcher script above. This image build will take 5-20 minutes.

docker build --tag 'discourse_ose' /var/discourse/image/base/

Next we create a new yaml template to update the relevant nginx configuration files when bootstrapping the environment.

cat << EOF > /var/discourse/templates/web.modsecurity.template.yml
run:
  - exec:
     cmd:
       - sudo apt-get install -y modsecurity-crs
       - cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
       - sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf
       - sed -i 's^\(\s*\)[^#]*SecRequestBodyInMemoryLimit\(.*\)^\1#SecRequestBodyInMemoryLimit\2^' /etc/modsecurity/modsecurity.conf
       - sed -i '/nginx/! s%^\(\s*\)[^#]*SecAuditLog \(.*\)%#\1SecAuditLog \2\n\1SecAuditLog /var/log/nginx/modsec_audit.log%' /etc/modsecurity/modsecurity.conf

  - file:
     path: /etc/nginx/conf.d/modsecurity.include
     contents: |
        ################################################################################
        # File:    modsecurity.include
        # Version: 0.1
        # Purpose: Defines mod_security rules for the discourse vhost
        #          This should be included in the server{} blocks nginx vhosts.
        # Author:  Michael Altfield <michael@opensourceecology.org>
        # Created: 2019-11-12
        # Updated: 2019-11-12
        ################################################################################
        Include "/etc/modsecurity/modsecurity.conf"
        
        # OWASP Core Rule Set, installed from the 'modsecurity-crs' package in debian
        Include /etc/modsecurity/crs/crs-setup.conf
        Include /usr/share/modsecurity-crs/rules/*.conf

  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /server.+{/
     to: |
       server {
         modsecurity on;
         modsecurity_rules_file /etc/nginx/conf.d/modsecurity.include;

EOF

And add this new template to our Discourse docker container yaml file's templates list

grep 'templates/web.modsecurity.template.yml' containers/discourse_ose.yml || sed -i 's%^\([^#].*templates/web.socketed.template.yml.*\)$%\1\n  - "templates/web.modsecurity.template.yml"%' containers/discourse_ose.yml

Your containers/discourse_ose.yml file should now look similar to this. Note the addition of the templates/web.modsecurity.template.yml line.

[root@osestaging1 discourse]# grep -A10 templates containers/discourse_ose.yml
templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml"
  - "templates/web.modsecurity.template.yml"
## Uncomment these two lines if you wish to add Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

## which TCP/IP ports should this container expose?
## If you want Discourse to share a port with another webserver like Apache or nginx,
## see https://meta.discourse.org/t/17247 for details
#expose:
##  - "80:80"   # http
##  - "443:443" # https
#  - "8020:8020"   # http backend

params:
[root@osestaging1 discourse]# 

discourse.opensourcecology.org DNS

Add 'discourse.opensourceecology.org' to the list of domain names defined for our VPN IP Address in /etc/hosts on the staging server.

In production, this will mean actually adding A & AAAA DNS entries for 'discourse' to point to our production server.

Nginx Vhost Config

Create the following nginx vhost config file to proxy connections sent to 'discourse.opensourceecology.org' to the unix socket file created by Discourse.

cat << EOF > /etc/nginx/conf.d/discourse.opensourceecology.org.conf
################################################################################
# File:    discourse.opensourceecology.org.conf
# Version: 0.1
# Purpose: Internet-listening web server for truncating https, basic DOS
#          protection, and passing to varnish cache (varnish then passes to
#          apache)
# Author:  Michael Altfield <michael@opensourceecology.org>
# Created: 2019-11-07
# Updated: 2019-11-07
################################################################################

# this whole site is a subdomain, so the below block for redirecting a naked
# domain does not apply here
#server {
#       # redirect the naked domain to 'www'
#       #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
#   #                   '$status $body_bytes_sent "$http_referer" '
#   #                   '"$http_user_agent" "$http_x_forwarded_for"';
#       #access_log /var/log/nginx/www.opensourceecology.org/access.log main;
#       #error_log /var/log/nginx/www.opensourceecology.org/error.log main;
#   include conf.d/secure.include;
#   include conf.d/ssl.opensourceecology.org.include;
#   listen 10.241.189.11:443;
#       server_name opensourceecology.org;
#       return 301 https://www.opensourceecology.org$uri;
#
#}

server {

		access_log /var/log/nginx/discourse.opensourceecology.org/access.log main;
		error_log /var/log/nginx/discourse.opensourceecology.org/error.log;

   include conf.d/secure.include;
   include conf.d/ssl.opensourceecology.org.include;
   #include conf.d/ssl.openbuildinginstitute.org.include;

   listen 10.241.189.11:443;
   #listen [2a01:4f8:172:209e::2]:443;

   server_name discourse.opensourceecology.org;

		#############
		# SITE_DOWN #
		#############
		# uncomment this block && restart nginx prior to apache work to display the
		# "SITE DOWN" webpage for our clients

#       root /var/www/html/SITE_DOWN/htdocs/;
#   index index.html index.htm; 
#
#       # force all requests to load exactly this page
#       location / {
#               try_files $uri /index.html;
#       }

		###################
		# SEND TO VARNISH #
		###################

#   location / {
#      proxy_pass http://127.0.0.1:6081;
#      proxy_set_header X-Real-IP $remote_addr;
#      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#      proxy_set_header X-Forwarded-Proto https;
#      proxy_set_header X-Forwarded-Port 443;
#      proxy_set_header Host $host;
#   }

		##################
		# SEND TO DOCKER #
		##################

	location / {
		proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
		proxy_set_header Host $http_host;
		proxy_http_version 1.1; 
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto https;
		proxy_set_header X-Real-IP $remote_addr;
	}

}
EOF

Varnish

TODO: actually include varnish

* https://meta.discourse.org/t/discourse-purge-cache-method-on-content-changes/132917

Backups

Add this block to /root/backups/backup.sh (TODO: test this)

#########
# FILES #
#########

# /var/discourse
echo -e "\tINFO: /var/discourse"
$MKDIR "${backupDirPath}/${archiveDirName}/discourse_ose"
time $NICE $TAR --exclude "/var/discourse/shared/standalone/postgres_data" --exclude "/var/discourse/shared/standalone/postgres_data/uploads" --exclude "/var/discourse/shared/standalone/backups" -czf ${backupDirPath}/${archiveDirName}/discourse_ose/discourse_ose.${stamp}.tar.gz /var/discourse/*

...

#############
# DISCOURSE #
#############

# cleanup old backups
$NICE $RM -rf /var/discourse/shared/standalone/backups/default/*.tar.gz
time $NICE $DOCKER exec discourse_ose discourse backup
$NICE $MV /var/discourse/shared/standalone/backups/default/*.tar.gz ${backupDirPath}/${archiveDirName}/discourse_ose/"

Hardening

Hardening TODO:

  1. iptables rules that prevent the discourse app from being able to initiate calls to the Internet (it should *only* be able to *respond* to queries) as we do for our apache backend by blocking non-established traffic from going through the OUTPUT table by the apache uid
    1. TODO: test an upgrade after this is done as well.
  2. OWASP CORS rules to prevent sqli/XSS/etc attacks as we do in apache
    1. update the install-nginx script so that it compiles nginx with mod_security (and probably downloads the OWASP CRS as well) https://github.com/discourse/discourse_docker/blob/416467f6ead98f82342e8a926dc6e06f36dfbd56/image/base/install-nginx
    2. add a new templates/web.modsecurity.yml file that updates the /etc/nginx/conf.d/discourse.conf file to enable mod_security (and add some blacklisted rules as-needed), similar to the existing web.socketed.template.yml file https://github.com/discourse/discourse_docker/blob/416467f6ead98f82342e8a926dc6e06f36dfbd56/templates/web.socketed.template.yml

SSL Cert

TODO: update the certbot cron script to add a Subject Alt Name for discourse.opensourceecology.org

Import Vanilla Forums

TODO: attempt to import our old forum's data into Discourse.

Looking Forward

This section will outline possible changes to be made to the Docker install/config in the future

Moving DBs outside docker

It's worthwhile to consider moving the redis and postgresql components of Discourse outside of the docker container [8]

MJ Feb 2019 Review

  • Legend: Check.png = exists, Check.pngCheck.png = good, Check.pngCheck.pngCheck.png = great
  • Check.pngQ&A plugin appears to be adequate, but does not have downvotes. Downvotes are important, as a knowledgeable person should ideally be able to downsize bull****. This is important for collaborative learning - and should be developed to approach the usefulness of Stack Exchange and Reddit. Would need to put development time into this.
  • Check.pngCheck.pngCheck.pngRating - appears excellent - [1]
  • Check.pngCheck.pngCheck.pngCommenting plugin - excellent, up with Disqus. [2]
  • Check.pngCheck.pngCheck.pngBug Tracking - a simple wiki/Discourse hack can be done by a Bugtracking or Known Bugs category on the wiki, and embedding a thread on that bug from Discourse, so discussion can happen, and when resolved, thread can be closed. We'd have to see in practice how this looks. That is the simplest way to go without installing yet another pieces of software, and using Discourse and Wiki hold most of the weight, the rest being Wordpress.

Cons

  • Free to try rather than really free? See last con at [3]

OSE Use Case

  • The generic OSE use case for transparency is using the Wiki for embedding all kinds of content, where the wiki is a proven and scalable tool for collaborative development - and a core tool in OSE's usage. With this said, it is useful to have various forms of content embedded in the wiki, so that we don't have to use many different platforms for different functions: we can just embed content from other common platforms. The intent is modular design where content can be reused and mixed throughout OSE's web presence.
  1. Embed individual Discourse threads on wiki pages. This way we upgrade content from wiki pages to live discussion - where content for discussion can be edited right in the wiki page. The intent of this is to improve the use of the Wiki as a development platform so that the wiki is more intuitive. See embed of thread example - [4]. This must allow any single thread from Discourse to be embedded.
  2. Rating of a service or product - in an open source franchise, products/services of collaborators can be rated. A simple tool like the wiki can have a rating feature - without having to use any other software. This is yet another way to make the wiki more functional and user-friendly. See example - [5]
  3. Upvoting - no evidence of Discourse serving this function well compared to Askbot. By upvoting, we mean simply that all the content remains visible, and a single solution is not marked. This allows users to pick nuggets from different answers - while allowing bulk filtering to occur before looking at the answer. From the OSE perspective, marking a question as resolved is not inclusive or abundant. What if someone else has a better solution? It may be that Discourse can be modified to do upvoting readily, or can simulate this function well - but we would have to see in practice if this is feasible.

2018-09 Review

In 2018-09, I (Michael Altfield) had just learned about Discourse as I was working on the phplist project. phplist's forums use Discourse. At the same time, Alex Au recommended to Marcin that we setup a replacement forum using Discourse.

Pros

  1. Very pleasant interface
  2. Very nice functionality ootb. Badges, user trust system for easy moderation, climbing ranks, love, at-calls (@), etc -- co-founder Jeff Atwood also founded Stack Exchange, so expect similar functionality
  3. Very popular. Many, many forums have switched to Discourse over the past several years
  4. Great selection of plugins & integrations (though no decent db/index for searching them) https://meta.discourse.org/c/plugin https://github.com/discourse
    1. ie: replace wordpress comments with a discourse thread. This may or may not be good.
      1. Example wordpress blog post: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/
      2. Corresponding discourse thread for the comments to the above post: https://meta.discourse.org/t/wp-discourse-dysfunctional-shows-only-start-the-discussion-at/36016
  5. Looks like we can import our content from Vanila https://meta.discourse.org/t/how-to-migrate-from-vanilla-to-discourse/27273
  6. Well-funded org that hosts their project (think wordpress.com) for many of their customers. The good here is that Discorse can pay a salary to devs, unlike many open source projects. But it's worth nothing that people choose to pay for hosting probably because it's Ruby on Rails, and a PIA to self-host.
  7. While not officially supported, it looks like users have setup Discourse behind varnish 4 [9]

Cons

  1. Ruby on rails
  2. They openly state that they're hard to install, and therefore _only_ support installation via a docker container [10]
  3. I'm seriously worried about the security of a project that thinks it's acceptable to use wget -qO- https://get.docker.com/ | sh as a step in their install guide [11]
  4. Discourse explicitly states that they only support newer devices. I'm concerned that means that we may make our content inaccessible to, say, that 6-year-old desktop running windows xp in the machine shop. Indeed, discourse only supports IE 11+, which came with Windows 8.1 in 2013--5 years ago. [12]
  5. If javascript is disabled, the site is read-only. JS is a requirement for posting, replying, etc. But because Discourse also functions as a mailing list, JS-free users can still contribute content in a limited way by replying to threads via email [13]

Neutral

  1. Project has been around for 5 years (initial release in 2013) https://en.wikipedia.org/wiki/Discourse_%28software%29

Noteable sites using Discourse

  1. Ubuntu https://discourse.ubuntu.com/
  2. Phplist https://discuss.phplist.org/
  3. Whonix https://forums.whonix.org/
  4. Manjaro https://forum.manjaro.org

See Also

References

Links

  1. https://docs.discourse.org- API Docs only (not very useful)
  2. https://meta.discourse.org/c/10-howto - "howto" tagged topics on meta.discourse.org
  3. https://meta.discourse.org/c/howto/faq/4 - Discourse FAQ
  4. https://meta.discourse.org/t/advanced-troubleshooting-with-docker/15927
  5. https://meta.discourse.org/t/where-are-all-the-discourse-logs/58022
  6. https://meta.discourse.org/t/discourse-moderation-guide/63116
  7. Civilized Discourse Construction Kit - positively biased post about Discourse - [6]
  8. https://www.slant.co/options/2789/~discourse-review
  9. https://forums.whonix.org/t/change-whonix-forum-software-to-discourse/1181