CHECKLIST: Setting up a new Discourse


When setting up a new Discourse instance, there are a number of steps which should be followed to ensure a consistent, secure output. While it’s possible to fully automate a process like this using tools such as Ansible, the efficiency of scripting the process is only realised if you’re doing this very frequently, and also you need to be prepared to repair the script frequently when small details change.


Another option, and the one I’ve chosen here, is the approach of creating a ‘checklist’ or ‘runbook’ which contains step-by-step commands to result in a consistent output. The other benefit of this compared to a script is that it also provides an opportunity for the sysadmin to make small adaptations on-the-fly, and to understand the process that has been gone through.


Place details here and the commands in the rest of the checklist will be auto-filled for you

Fully-qualified Domain name you wish to use for the Discourse server once set up

Name of the new non-root user you want to create on the server

The ssh-import-id SSH Key identity you want to use for the new non-root user (Optional)

(ssh-import-id is able to pull SSH public keys from GitHub so a good way to do this is to upload an SSH public key to your GitHub account and use the identity gh:your-username in this box.

Create the server

Discourse recommend a server running Ubuntu Long Term Support (LTS), and the expectation would be to use the most recent LTS version. At the time of writing that is Ubuntu 22.04.

You can create your server on any cloud platform, but I have included some steps below for creating the server on DigitalOcean using their doctl command line tool. (note: Pavilion doesn’t receive any remuneration or affiliate income from DigitalOcean, I just use it at the moment)

Create server on DigitalOcean (optional)

Click here to expand DigitalOcean server setup section


This section of the checklist uses the doctl command-line tool for Digital Ocean to create a project and provision the server. You will need to have doctl installed and set up with credentials to connect to your DigitalOcean account.

Extra DigitalOcean placeholder values

Choose a name for the project, which will be used for naming Digital Ocean project and the droplet (server)

This is the SSH key fingerprint that is in your Digital Ocean account, for initial root access only

Create the DigitalOcean project

doctl projects create doctl projects create \
   --name =PROJECT_NAME= \
   --purpose "Web Application"

Create an Ubuntu 22.04 LTS Digital Ocean droplet in that project

doctl compute droplet create =PROJECT_NAME=-discourse \
    --size s-2vcpu-2gb \
    --image ubuntu-22-04-x64 \
    --region lon1 \
    --ssh-keys =DO_SSH_PUBKEY= \

note: you can get info about available --size, --image and --region arguments with:
doctl compute size list
doctl compute image list-distribution
doctl compute region list
Region location may need to vary according to needs of customer
More info: doctl compute droplet create :: DigitalOcean Documentation

Move the new Droplet into your Project

At present you need to move the Droplet into the project manually in the UI, because although it’s possible from the command line using the doctl projects resources assign ... command, you would need both the Project and Resource UUID for this and it starts to get tedious.

Enable Digital Ocean Firewall

For now this is a manual step. You may already have a firewall created in the DO panel, which you can add to the Droplet. Information on doing this programmatically is here How To Secure Web Server Infrastructure With DigitalOcean Cloud Firewalls Using Doctl | DigitalOcean

SSH access to the droplet

doctl simplifies SSH access for you by aliasing droplet name to user/IP

doctl compute ssh =PROJECT_NAME=-discourse

if you’re using the snap installed version of doctl then you need to run snap connect doctl:ssh-keys :ssh-keys first to make it work.

Domain registration and DNS record setup

If you haven’t already registered the Top Level Domain (TLD) that you are going to use for the project, you should do this now.

If you have a domain you want to use, set up an A record in the DNS settings pointing from your =DOMAIN_NAME= to the IP address which your server is located at. This IP address should be visible in the control panel of the cloud platform in which you have created your server.

Log into the server

ssh root@=DOMAIN_NAME=

Set up the server

based on

all the below commands are executed over SSH on the Droplet

Some useful initial timesaving command aliases

Add doupdates manual updater for the OS

This adds a command to etc/profile that speeds up running updates on your servers

echo "alias doupdates='sudo apt-get update && \
    sudo apt-get -y dist-upgrade && \
    sudo apt autoremove && \
    sudo apt autoclean'" >> /etc/profile;source /etc/profile

Add a command to quickly enter the discourse app container

echo "alias app='sudo su && cd /var/discourse && \
   ./launcher enter app'" >> /etc/profile;source /etc/profile

Automatically cd to `/var/discourse/ on login (where else would you be going?)

echo "cd /var/discourse/" >> /etc/profile;source /etc/profile

Load those aliases into the current shell session

source /etc/profile

Ubuntu Updates

using the aliases we’ve installed, updating server OS is now a single command:


Non-root user setup

This section sets up a non-root user, which is what we will in future use for all logins to the server. We will disable root logins in a later step, for additional security.

You should be logged in over SSH, as root, to start with.

create a non-root user ‘=NEW_USERNAME=’

After this command you will be prompted for a password. I make up a long complex random password and then forget it because you will never need to use it for this user to login or achieve sudo.

adduser =NEW_USERNAME=

make the new user a sudoer

usermod -aG sudo =NEW_USERNAME=

edit sudo config so that discourse user can sudo without password

This is not a security compromise since the user can only log in using an SSH key, which is very secure


adding the following after the last line


create an .ssh directory for the new user, and change the ownership of that directory to the new user

mkdir /home/=NEW_USERNAME=/.ssh && \

become the new user


import the required SSH public key to this user’s authorized_keys file

ssh-import-id =NEW_USER_SSH_IMPORT=

check it worked (optional)

cat ~/.ssh/authorized_keys

This should list the new SSH key as ‘authorized’


Log out and try logging in as the new user

Plain SSH login


Should log in without requiring a password.

doctl login

doctl compute ssh =PROJECT_NAME=-discourse --ssh-user =NEW_USERNAME= 

Should return =NEW_USERNAME=@=PROJECT_NAME=-discourse:~$

SSH security configuration

edit the SSH config

sudo nano /etc/ssh/sshd_config

edit the SSH config so that the following are set to no and are uncommented
PermitRootLogin no
PasswordAuthentication no

then apply the changes

sudo service ssh restart

test this by logging out and back in again


root login should now fail

doctl compute ssh =PROJECT_NAME=-discourse --ssh-user root

password login should fail

doctl compute ssh =PROJECT_NAME=-discourse --ssh-user somerandomusername

test login as =NEW_USERNAME= should still work

doctl compute ssh =PROJECT_NAME=-discourse --ssh-user =NEW_USERNAME=

Install Discourse

The following simply follows the Discourse simple installer at discourse/ at main · discourse/discourse · GitHub

sudo -s
git clone /var/discourse
cd /var/discourse

Run Discourse Setup which will install Docker if needed, and then it proceeds with the rest of installation.



You will need a hostname, not an IP address, in order to set up Discourse properly. Discourse setup will ask you for this hostname as you go through the steps, and you can enter this:


Then you will be taken through steps including Admin email, SMTP settings, and LetsEncrypt.

Assuming all the above has gone correctly, you should now have a new Discourse at


Congratulations :confetti_ball: :tada: :fireworks: :raised_hands: :clinking_glasses:

:flight_departure: Next Steps: CHECKLIST: Next steps after installing a new Discourse


Preamble from the original post moved down here into the comments:

I’m reading The Checklist Manifesto by Atul Gawande which is really excellent and has inspired me to ensure as much of Pavilion work as possible has a clear checklist, so we do stuff quickly and get it right. (These are for anyone to use, but it’s fine if you have a different way of doing things and don’t want to use them)

I found a discourse-placeholder-theme-component on Meta, which the Discourse team use to create their ‘runbooks’ (which I think in their parlance are some thing different to - something we have been looking at for our own work)

I am here using Digital Ocean and their own doctl CLI, but eventually we might want to use other cloud providers and therefore a more ‘provider-agnostic’ approach will be needed.


Love this guide and tips. Is there any reason to not have it in though?

1 Like

I put it here because I’ve seen too many posts on Meta being moved, deleted, and generally fucked about with. Usually without asking if it’s ok.

If I go to the effort of writing something like this, I don’t want it deleted in a year’s time, I want control over it.


Well, that is the reality of the wiki world. The primary author loses control but gains collaborators.

I like it here, it is fine here. Let us leave it here. What @pacharanero said is valid, let us have some control over the things we create and posting here gives us that control.

1 Like

In 8 years of posting on Meta I’ve not seen a single edit to my posts that was helpful. I can’t wikify stuff myself as I am only TL1.

I will be retaining control of what I create, sorry. I don’t work for CDCK and I have no interest in it.