First of all, you should follow official Docker-based installation guide to deploy your Discourse. I use mina to deploy my Discourse to my VPS because it's easier and faster for me.

  1. I follow Discourse Advanced Developer Install Guide and make sure Discourse can run on localhost. My Discourse version at the time is 1.0.0beta4.
  2. Buy VPS with specifications:
    • 2 CPU @2,4 GHz
    • 1 GB RAM
    • 20 GB HDD
    • 256 Swap Memory
    • Ubuntu 14.04
Setup VPS
  1. first of all, login as root before run the commands below.
    stop unused service and create new standard user

    sudo service apache2 stop
    sudo service mysql stop
    adduser myexampleuser
  2. Install PostgreSQL Database

    sh -c "echo 'deb precise-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
    wget --quiet -O - | sudo apt-key add -
    wget --quiet -O - | apt-key add -
    apt-get update
    apt-get install postgresql-common
    apt-get install postgresql-9.3 libpq-dev postgresql-contrib-9.3
  3. Set Postgre SQL Language
    export LANG="en_US.UTF-8"
    service postgresql restart
  4. Edit /etc/postgresql/9.3/main/pg_hba.conf, and find the line below:
    local   all   all   peer
    Change to this:
    local   all   all   md5
  5. Restart PostgreSQL and Create database with username and password

    sudo service postgresql restart
    sudo -u postgres createuser mydatabaseuser -s -P
  6. Recreate template1 to use UTF-8 based on these instructions.
    UPDATE pg_database SET datistemplate = FALSE WHERE datname = 'template1';
    DROP DATABASE template1;
    UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template1';
    \c template1
    UPDATE pg_database SET datallowconn = FALSE WHERE datname = 'template1'
  7. Create Discourse database

    createdb -U mydatabaseuser discourse_production
  8. Install Nginx, NodeJS, Npm and Redis.
    apt-get install nginx
    apt-get install nodejs
    apt-get install npm
    apt-get install redis-server

    // run command below to start redis
    sudo service redis-server start
  9. Install ImageMagick and image optimizer
    apt-get install ImageMagick
    apt-get install libxml2 libpq-dev g++
    apt-get install pngquant
    apt-get install jhead
    apt-get install jpegoptim
    apt-get install jpegtran
    apt-get install libjpeg-progs
    apt-get install gifsicle

    ln -s /usr/bin/nodejs /usr/bin/node
    npm install -g svgo
  10. Install Rbenv and Ruby dependencies, taken from Digital Ocean article.

    apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev
  11. Setup Rbenv

    git clone git:// .rbenv
    echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
    echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

    git clone git:// ~/.rbenv/plugins/ruby-build
    echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bash_profile
    source ~/.bash_profile
  12. Setup Server for Mina

    mkdir -p apps/discourse
    ssh-keyscan -H >> ~/.ssh/known_hosts
  13. Done. exit from VPS.

Setup Mina The Deployer

Mina is really fast deployer and server automation tool. Mina only creates one SSH session per deploy, minimizing the SSH connection overhead.
  1. Clone Discourse

    git clone
    cd discourse
  2. Add mina to Gemfile

    # Gemfile
    gem 'mina'
  3. Generate mina config file inside Discource directory

    mina init
  4. Configure Thin, Sidekiq, and Mina
    I've experiences my VPS out of memory multiple times. To prevent that happen again, I set RUBY_GC_MALLOC_LIMIT=25000000, 2 thin server, and 5 sidekiq workers. Here are my complete mina, thin, and sidekiq configuration

    Thin config

    # config/thin.yml
    chdir: /home/myexampleuser/apps/discourse/current
    environment: production
    pid: /home/myexampleuser/apps/discourse/shared/pids/
    socket: /home/myexampleuser/apps/discourse/tmp/thin.sock
    servers: 2
    daemonize: true
    onebyone: true

    Sidekiq config

    # config/sidekiq.yml
    :concurrency: 5
    :daemon: true
    :logfile: /home/myexampleuser/apps/discourse/shared/log/sidekiq.log
    :pidfile: /home/myexampleuser/apps/discourse/tmp/pids/

    Mina config (Gist)

    # config/deploy.rb

    require 'mina/bundler'
    require 'mina/rails'
    require 'mina/git'
    require 'mina/rbenv'

    set :term_mode, nil
    set :rails_env, 'production'

    set :domain, ''
    set :deploy_to, '/home/myexampleuser/apps/discourse'
    set :repository, ''
    set :branch, 'master'

    set :shared_paths, ['config/discourse.conf', 'log', 'public/uploads', 'public/backups', 'tmp/pids']
    set :user, 'myexampleuser' # Username in the server to SSH to.
    set :forward_agent, true # SSH forward_agent.

    task :environment do

    task :setup => :environment do
    queue! %[mkdir -p "#{deploy_to}/#{shared_path}/log"]
    queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/log"]

    queue! %[mkdir -p "#{deploy_to}/#{shared_path}/config"]
    queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/config"]
    queue! %[touch "#{deploy_to}/#{shared_path}/config/discourse.conf"]

    queue! %[mkdir -p "#{deploy_to}/#{shared_path}/public/uploads"]
    queue! %[mkdir -p "#{deploy_to}/#{shared_path}/public/backups"]
    queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/public/uploads"]
    queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/public/backups"]

    queue! %[mkdir -p "#{deploy_to}/tmp/pids"]
    queue! %[chmod g+rx,u+rwx "#{deploy_to}/tmp/pids"]

    desc "Deploys the current version to the server."
    task :deploy => :environment do
    deploy do
    invoke :'git:clone'
    invoke :'deploy:link_shared_paths'
    invoke :'bundle:install'
    invoke :'rails:db_migrate'
    invoke :'rails:assets_precompile'
    invoke :'deploy:cleanup'

    to :launch do
    # uncomment if you want restart thin and on deploy
    #invoke :'sidekiq:restart'
    #invoke :'thin:restart'

    namespace :thin do
    desc "start thin server"
    task :start => :environment do
    queue "cd #{deploy_to}/#{current_path}/ && RUBY_GC_MALLOC_LIMIT=25000000 bundle exec thin -C config/thin.yml start"

    desc "stop thin server"
    task :stop => :environment do
    queue "cd #{deploy_to}/#{current_path}/ && RUBY_GC_MALLOC_LIMIT=25000000 bundle exec thin -C config/thin.yml stop"

    desc "restart thin server"
    task :restart => :environment do
    queue "cd #{deploy_to}/#{current_path}/ && RUBY_GC_MALLOC_LIMIT=25000000 bundle exec thin -C config/thin.yml restart"

    namespace :sidekiq do
    desc "start sidekiq"
    task :start => :environment do
    queue "cd #{deploy_to}/#{current_path}/ && bundle exec sidekiq -C config/sidekiq.yml -e production"

    desc "stop sidekiq"
    task :stop => :environment do
    queue "cd #{deploy_to}/#{current_path}/ && bundle exec sidekiqctl stop /home/myexampleuser/apps/discourse/tmp/pids/"

    desc "restart sidekiq"
    task :restart => :environment do
    invoke :'sidekiq:stop'
    invoke :'sidekiq:start'

  5. Run Mina Setup and deploy Command

    mina setup
    mina deploy
  6. login to VPS and copy content from config/discourse_defaults.conf to ~/apps/discourse/shared/config/discourse.conf and replace with these configuration.

    db_name = discourse_production
    db_username = mydatabaseuser
    db_password = mydatabasepassword
    hostname =
  7. login as root and copy Nginx configuration

    cd ~/apps/discourse/current
    cp config/ /etc/nginx/conf.d/
    cp config/nginx.sample.conf /etc/nginx/conf.d/discourse.conf
  8. Configure Nginx
    Open /etc/nginx/conf.d/discourse.conf and replace with these configuration.

    # Only use 2 Thin server
    upstream discourse {
    server unix:/home/myexampleuser/apps/discourse/tmp/thin.0.sock;
    server unix:/home/myexampleuser/apps/discourse/tmp/thin.1.sock;

  9. Restart Nginx

    sudo service nginx restart
  10. Exit from VPS, start Sidekiq and Thin

    mina sidekiq:start
    mina thin:start
  11. Done! :)