Skip to content

Install and Run Discourse behind Nginx the Right Way, First Time!

Posted in Server

Everyone says it is simple. It is NOT, even especially when you want to run Discourse behind a front-facing server like Nginx. After going through enough pain to get up and running a Discourse instance on time, see how to Install and Run Discourse behind Nginx the Right Way the First Time!

This tutorial makes these assumptions, so if you meet any of them, you’re good to know:

  • You’re on a VPS such as a Droplet from Digital Ocean with specs
    • 1 Gig or more RAM
    • 1 Core CPU or more
  • You’re on Ubuntu 16.04 LTS
  • You know how to work your way around your VPS
  • You have a myemail@yourdomain.co email account at Zoho already, sending emails
  • You have Nginx installed
  • You are serving website(s) already with Nginx
  • You want Discourse installed on a subdomain, such as yologhana.khophi.co
  • We use yologhana.khophi.co as the example domain

If you’re looking to install Discourse on a fresh droplet, this might not be what you want. Check out the other tutorials on how to do so.

Our Itenary

This is how you might wanna approach it, which worked for me:

  • Send Discourse notification emails with Zoho Mail
    • This is important so that when someone signs up, they can receive an email from Discourse to verify their account.
  • Front-facing server is Nginx (Discourse uses Nginx too in its Docker instance)
  • Install Docker Engine
  • Install Discourse

So, without much ado, let’s get our discourse running, beginning with the simple steps.

Setting up Email

Probably a convention now, emails you send messages from but don’t intend to receive or reply to messages are usually named somewhere along the lines of ‘No Reply’.

So our email we’ll be sending user notifications from will be noreply@khophi.co

Using an email address with a . (dot) in the name failed several times i.e no.reply@khophi.co. I couldn’t find any docs saying that ain’t allowed, and no errors were or are thrown, except I could NOT authenticate. I found this the hardway.

Maybe I didn’t do something right somewhere, but with a dot never worked for me.

Adding an email account to your Zoho should be simple. I am of the assumption that you already have something like myemail@yourdomain.com so you’re simply adding another user.

Zoho Mail Add User
Zoho Mail Add User

What password to use? All-numbers password didn’t work for me also. It is hard to tell at the moment, but it just didn’t work, always had the Authentication Error.

Email is out of the way.

A simple way to verify if your Zoho new email user is functioning, simply open a new Incognito (or something similar) tab in your browser, visit mail.zoho.com, log in with your new email user.

We’ll want to send emails using the noreply@khophi.co email address, so make sure you’ve opened up the POP in the new email account.

Discourse
Green means Go!

 

Install Docker

Straightforward:

The last line is to ensure and test if docker is properly installed.

Add the current user to the docker group like so:

Done with Docker!

Discourse, Baby!

Installing Discourse is a straightforward process too, except information relating to how to get it happening ‘straightforwardly’ is not easily found.

Let’s go!

Then, we need to manually prepare our app.yml file.

We want to install Discourse as a standalone. By manually creating our app.yml we get to tweak things a little bit.

The app.yml gives us a lot of options, however, as you go through, notice what we comment out, such as:

  • We don’t want Rate Limiting with our Discourse Standalone
  • SSL will be handled by the outer Nginx, so we also disable that
  • The Discourse instance is exposed on port 25654:80 on which our outer Nginx will be mapped against. The idea is so that we can share Discourse with another web server like Apache or Nginx which don’t joke with their port 80.
    • On my Droplet, I only have 3 ports open, including port 80, through which EVERY web request incoming goes through. That port is so crucial I can’t just kick my outer Nginx off that and replace with Discourse. That’s where what port to expose Discourse instance on is crucially useful!

In the app.yml that shows on screen, we go like this:

I don’t just get it. Why is the configuration file not a JSON object instead?

Obviously, YAML has issues and isn’t intuitive to the average dumb guy like myself. A clear sign Discourse has been rigged for only the Elite in the society.

The above is the complete app.yml I use, just replace the dummy parts with your own. Remember from above what you need to put in the password and username fields. The email should be without dots and the password not entirely numeric.

On a 1 Gig RAM Droplet, you might consider doing these tunings as per recommendations from Digital Ocean.

In the env section of the configuration file, set db_shared_buffers to 128MB and UNICORN_WORKERS to 2 so you have more memory room, like so

db_shared_buffers: "128MB" and UNICORN_WORKERS: 2

Tuning these memory settings will optimize Discourse performance on a 1 GB Droplet.

In the run block we’ve enabled an exec function to run. This is important to get emails sending for the first time. We can disable and rebuild later on, but for the first time, keep that line uncommented.

If you have that configuration tweaked, checked and rechecked, move onto the next part which deals with bringing up our app container.

We disabled the "templates/web.ratelimited.template.yml" because, our Inner Nginx tends to think only one IP address is trying to make multiple connections, which isn’t true.

See, when the Outer Nginx takes the incoming request, it funnels all the request to the Inner Nginx as a single user from a single IP. This gives the inner Nginx the impression a user is trying to bombard it with recurring multiple requests.

This causes Nginx to go in a stalemate. Disabling this here, but enabling it in the outer Nginx will actually be what we’re looking for.

If our Discourse instance is accepting requests from the public, there won’t be any need to remove the rate limiting, as incoming connections will be from random multiple users which won’t trigger the flood error you normally get.

 

[wp_ad_camp_1]

 

Bootstrapping

Our app needs to be bootstrapped first. We’re still in the /var/discourse directory. That can be achieved with this:

sudo ./launcher bootstrap app

That will take some time. When done, we go ahead to bring it up with:

sudo ./launcher start app

Configure Nginx

This configuration is for the outer Nginx. We saw how to manage the inner Nginx a little bit in the previous section.

With that removal, the change applied to inner Nginx configuration when the app was built.

I use the express ‘Inner Nginx’ to refer to the Nginx bundled with Discourse’s Docker image. That Nginx is different from the ‘Outer Nginx’, the one currently facing the world.

This part, we’ll focus on the Outer Nginx configuration.

In the /etc/nginx/sites-enabled/ you should see a discourse.conf file. If not available there, check the /etc/nginx/sites-available/ directory for the file.

If you still don’t see any, create a file, namely discourse.conf in the /etc/nginx/sites-available/ folder and update it with these content.

The above configuration uses SSL generated by LetsEncrypt. We’re in 2016, and if you don’t happen to have your sites running on HTTPS, then ask yourself why, because SSL is free and extremely easy to generate these days.

Generating an SSL for your site is out of the scope of this article, but there are plenty of articles out there to this effect.

You need the proxy_set_header X-Forwarded-Proto $scheme; to ensure your Sidekiq works properly. Without this, you’ll come across the Forbidden when you try to issue actions in your Sidekiq dashboard

Now that our outer Nginx too is properly setup, a restart will be needed after we check our configurations for errors, so:

sudo nginx -t

If any errors, fix them. If all goes well,

sudo service nginx restart

Try accessing discourse.yourdomain.co in your browser and you should be greeted with Discourse with the opportunity to log in with your account.

If you can’t log into your account, you might wanna reset it. Follow the steps below:

Run this command from console:

rake admin:create

You will be asked for Email, enter the email of an existing account.

Now you will be asked: User with this email already exists! Do you want to reset the password for this email? (Y/n). Press enter to continue.

Provide the new password and confirm your password.

If it worked, you’ll see Account updated successfully!

Now switch back to the browser and log in again. There you go!

Discourse
Discourse in Action