An Open Source Forum with Discourse and Nanobox

Discourse is a very popular open source forum because of its robust features. The amount of stuff you get for the price tag with Discourse is quite amazing and the team behind it has done a great job.

Discourse has everything you would expect from a full-featured forum platform. And for anything you don't get out of the box, there are tons of both great official and community plugins.

Installation (with Discourse)

If you're interested, Discourse offers paid plans to get your forum installed, configured and hosted quickly. This is a good option for anyone wanting to get a forum up right away with little work.

The next option is their officially supported Docker installation. They've put a lot of work into this to make it as easy as possible (but I'll be showing you an easier way).

Installation (with Nanobox)

This article outlines how to create and deploy a Discourse forum using Nanobox. If you're not familiar with Nanobox, it's a micro-platform that allows you to build, deploy, and manage your app anywhere.

I feel at this time I need to bring up one very important thing... What I'll show you here is an unsupported installation and highly frowned upon by the Discourse team. They have an official supported installation method (mentioned above), which is the only method for which they provide support.

With that out of the way, if I haven't scared you off (yet), let's get started!

This tutorial assumes you already have a Nanobox account and have downloaded Nanobox. If you need to, create an account, and download Nanobox Desktop before you begin.

Getting Started

I'll cover two separate methods of installing Discourse with Nanobox:

Using the Quickstart

First things first. Clone the nanobox-discourse quickstart and change into its directory:

git clone https://github.com/nanobox-quickstarts/nanobox-discourse && cd nanobox-discourse

From here you have a few options:

I would suggest you do these in order, but you're welcome to skip ahead.

Run Discourse Locally

Before you do anything, add a convenient way to access your application from the browser:

nanobox dns add local discourse.local

Once you have the application cloned you can simply run the following:

# start your dev env and drop into a console
nanobox run

# migrate your data
rake db:migrate

# start your server
rails s

You should now be able to visit your application at discourse.local

Note: You'll likely need to add an admin user to get past the welcome screen. The easiets way to do this is from a nanobox console (nanobox run) do rake admin:create

Stage Discourse Locally

Note: Discourse takes a ton of resources. Unless you've got a lot of resources dedicated to it, you might have some problems getting it to stage.

Nanobox lets you stage your application in a production setting before deploying it. To simulate running in production you'll want to tell rails to run in production:

nanobox evar add dry-run RAILS_ENV=production
nanobox deploy dry-run

This spins up an environment that is an exact replica of a production environment.

Deploy Discourse to Production

Note: Discourse takes a ton of resources. You'll need to scale your application to at least 1GB of ram before you can deploy (I would recommend 2GB).

Before you can deploy to production you'll need to create a new app on Nanobox. Once your app's created, link it to your local codebase and deploy:

nanobox remote add <your-app-name>
nanobox deploy

This deploys your app to production. Nanobox uses the boxfile to provision and configure the same infrastructure you're app's already been running in.

That's it!

If you have any questions or run into any issues please reach out!

Note: You'll likely need to add an admin user to get past the welcome screen. The easiets way to do this is from a nanobox console (nanobox console web.main) do rake admin:create

Discourse From Scratch

To run Discourse from scratch you'll first need to clone Discourse and cd into the directory:

git clone git@github.com:discourse/discourse.git && cd discourse

Add a Boxfile

Nanobox uses a simple yml config file called a boxfile. The boxfile is used to describe your applications infrastructure to Nanobox.

Discourse has quite a few requirements to run. I'll add comments to the boxfile highlighting important configurations:

run.config:
  engine: ruby
  extra_packages:
    - git
    - nodejs
    - nginx
    - ImageMagick
    - optipng
    - jpegoptim
    - gifsicle
    - jhead
  extra_steps:
    - yarn install
  extra_path_dirs:
    - node_modules/.bin
  cache_dirs:
    - .bundle
    - vendor/bundle
    - node_modules

#
deploy.config:
  before_live:
    web.main:
      # - bundle exec rake db:setup_or_migrate
      - mkdir -p tmp/ember-rails
      - touch tmp/ember-rails/ember.js
      - touch tmp/ember-rails/ember-data.js
      - chmod +w tmp/ember-rails/*
      - bundle exec rake db:migrate RAILS_ENV=production
      - bundle exec rake assets:precompile --trace RAILS_ENV=production PRECOMPILE=true

#
web.main:
  start:
    nginx: nginx -c /app/config/nginx.conf
    puma: bundle exec puma -C /app/config/puma.rb
  writable_dirs:
    - log
    - plugins
    - public
  network_dirs:
    data.assets:
      - public/assets
      - tmp
  log_watch:
    rails[discourse]: log/production.log
    puma: log/puma.log

#
worker.main:
  start: bundle exec sidekiq
  writable_dirs:
    - log
    - public
  network_dirs:
    data.assets:
      - tmp
  log_watch:
    sidekiq: log/sidekiq.log

#
data.db:
  image: nanobox/postgresql:9.4

#
data.assets:
  image: nanobox/unfs

#
data.redis:
  image: nanobox/redis

Run Discourse Locally

To run Discourse locally, copy the boxfile from above. Place it at the root of your project's directory and run the following command:

nanobox run

Configure Discourse

Before your app will run correctly, you'll need to update some of the existing configurations, and add some of your own.

discourse.conf

Discourse uses a discourse.conf file to manage most of the applications settings. Although not everything here is needed to run the application locally, go ahead and configure it now to get it out of the way.

Copy Discourse's example config to use as your own:

cp config/discourse_defaults.conf discourse.conf

Nanobox automatically generates some environment variables for you to use. Inside your new discourse.conf find and add the following evars:

db_host = <%= ENV['DATA_DB_HOST'] %>
db_name = gonano
db_username = <%= ENV['DATA_DB_USER'] %>
db_password = <%= ENV['DATA_DB_PASS'] %>
hostname = <%= ENV['DISCOURSE_HOSTNAME'] || "www.example.com" %>
smtp_address = <%= ENV['DISCOURSE_SMTP_ADDRESS'] %>
smtp_port = <%= ENV['DISCOURSE_SMTP_PORT'] %>
smtp_domain = <%= ENV['DISCOURSE_SMTP_DOMAIN'] %>
smtp_user_name = <%= ENV['DISCOURSE_SMTP_USER_NAME'] %>
smtp_password = <%= ENV['DISCOURSE_SMTP_PASSWORD'] %>
redis_host = <%= ENV['DATA_REDIS_HOST'] %>

This will give your application everything it needs to run across all environments.

Connecting to the Database

To connect Discourse to your database, update the database.yml. Nanobox generates environments variables for you to use here:

development:
  prepared_statements: false
  adapter: postgresql
  database: gonano
  min_messages: warning
  pool: 5
  timeout: 5000
  host: <%= ENV['DATA_DB_HOST'] %>
  username: <%= ENV['DATA_DB_USER'] %>
  password: <%= ENV['DATA_DB_PASS'] %>
  host_names:
    ### Don't include the port number here. Change the "port" site setting instead, at /admin/site_settings.
    ### If you change this setting you will need to
    ###   - restart sidekiq if you change this setting
    ###   - rebake all to posts using: `RAILS_ENV=production bundle exec rake posts:rebake`
    - "localhost"

The pieces that need to be changed here are database, host, username, and password.

Use the default database gonano which is generated when adding a data component. This way you won't need to create a new database, and deploy to production is a little easier.

If you decide to use discourse_development you'll need to create your database first. When it's time to deploy you'll need a special rake task that does this for you as well.

Make Your App Accessible

Next, you'll need to add the following to your config/boot.rb:

# NANOBOX: change the default binding from localhost to 0.0.0.0
require 'rails/commands/server'
module Rails
  class Server
    def default_options
      super.merge(Host: '0.0.0.0', Port: 8080)
    end
  end
end

This tells Rails to listen on all available hosts. This makes the application accessible outside the VM.

Note: If your version of Discourse is using Rails 5+, this method doesn't work anymore. Later, when starting your server you'll need to start with rails s -b 0.0.0.0 -p 8080.

Add Local DNS

Finally, add a DNS alias to make your application easily accessible from a browser. You do this with the nanobox dns command:

nanobox dns add local discourse.local
Up and Running

With all that configuration in place, it's finally time to start up Nanobox for some final steps.

The nanobox run command will create your local development environment. This mounts your local code base into a VM where your infrastructure is running.

nanobox run

Once nanobox run has completed you're dropped into a Nanobox console. From in here the final thing you'll need to do is migrate your data and then start your server:

rake db:migrate
rails s

Once your server is running you should be able to visit your application at discourse.local (or whatever DNS you setup above).

Note: You'll likely need to add an admin user to get past the welcome screen. The easiest way to do this is from a nanobox console (nanobox run) do rake admin:create

Configure Discourse for Production

With everything running smoothly locally, it's time to prepare the application to run in production.

Nginx and Puma

To ensure Discourse runs as fast as possible, it's ideal to run it behind an Nginx reverse proxy, using Puma as the web server. To set this up we'll just need to add an nginx.conf file, and update the existing puma.rb.

Puma

in the config/puma.rb file, comment out the default Discourse config and add the following:

threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
port        ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
plugin :tmp_restart
Nginx

To configure nginx simply add a config/nginx.conf with the following:

worker_processes 1;
daemon off;

events {
    worker_connections 1024;
}

http {
    include /data/etc/nginx/mime.types;
    sendfile on;

    gzip              on;
    gzip_http_version 1.0;
    gzip_proxied      any;
    gzip_min_length   500;
    gzip_disable      "MSIE [1-6]\.";
    gzip_types        text/plain text/xml text/css
                      text/comma-separated-values
                      text/javascript
                      application/x-javascript
                      application/atom+xml;

    # Proxy upstream to the puma process
    upstream rails {
        server 127.0.0.1:3000;
    }

    # Configuration for Nginx
    server {

        # Listen on port 8080
        listen 8080;

        root /app/public;

        try_files $uri/index.html $uri @rails;

        # Proxy connections to rails
        location @rails {
            proxy_pass         http://rails;
            proxy_redirect     off;
            proxy_set_header   Host $host;
        }
    }
}

Stage Discourse Locally

Note: Discourse takes a ton of resources. Unless you've got a lot of resources dedicated to it, you might have some problems getting it to stage.

Once you're ready to deploy to production it's recommended you stage your app to ensure it works.

Normally, you would need to configure a production server and deploy there. Nanobox allows you to simulate a production environment from the safety of your own machine.

Before staging locally you'll need to make one change to Discourse. Open the config/initializers/100-verify_config.rb and comment out the section that checks to see if assets have been precompiled:

#   if !Dir.glob(File.join(Rails.root,'public','assets','application*.js')).present?
#     puts <<END
#
#       Assets have not been precompiled. Please run the following command
#       before starting the rails server in production mode:
#
#           rake assets:precompile
#
# END
#
#     raise "Assets have not been precompiled"
#   end

Since we're compiling after the deploy this check would fail, causing the deploy to fail.

Finally, just before staging locally, make sure Rails is running in production mode:

nanobox evar add dry-run RAILS_ENV=production
nanobox deploy dry-run

This fires up a local staging environment and configures it exactly as it will be when deployed to production. Once staged (and working) it's finally ready to deploy to production.

Deploy to production

Note: Discourse takes a ton of resources. You'll need to scale your application to at least 1GB of ram before you can deploy (I would recommend 2GB).

Before you can deploy to production you'll need to launch a new application on Nanobox.

Once your app is created link your local codebase to your new application:

nanobox remote add <your app name>

Before you deploy, you'll need to tell Discourse to run in production mode. Do this by going to the config > environment variables page from the dashboard and add the RIALS_ENV evar and set it to `production:

rails_env

Note: You can also add environment variables via Nanobox desktop with nanobox evar add KEY=VALUE

With your app created, and set to run in production you can deploy with:

nanobox deploy

Using the boxfile, Nanobox will create the same environment in production you've been using locally.

That's it!

At this point, you should have your very own Discourse forum up-and-running.

Note: You'll likely need to add an admin user to get past the welcome screen. The easiest way to do this is from a nanobox console (nanobox console web.main) do rake admin:create

Help!

If you've run into any issues, or have any problems please reach out, I'd love to help!

Posted in Ruby, Rails, Discourse, Forum, Nanobox, OpenSource, Open-Source