Update 2020-05-10: This tutorial is based on old version Discourse and Mina. Not sure if this tutorial is still working.
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.
Preparations 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.
Buy VPS with specifications:
2 CPU @2,4 GHz 1 GB RAM 20 GB HDD 256 Swap Memory Ubuntu 14.04 Setup VPS 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
Install PostgreSQL database.
sh -c "echo 'deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -
wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | apt-key add -
apt-get update
apt-get install postgresql-common
apt-get install postgresql-9.3 libpq-dev postgresql-contrib-9.3
Set PostgreSQL language.
export LANG="en_US.UTF-8"
service postgresql restart
Edit /etc/postgresql/9.3/main/pg_hba.conf, and find the line below.
local all all peer
Change to this line below.
local all all md5
Restart PostgreSQL and Create database with username and password.
sudo service postgresql restart
sudo -u postgres createuser mydatabaseuser -s -P
Recreate template1 to use UTF-8 based on these instructions .
UPDATE pg_database SET datistemplate = FALSE WHERE datname = 'template1' ;
DROP DATABASE template1 ;
CREATE DATABASE template1 WITH TEMPLATE = template0 ENCODING = 'UNICODE' ;
UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template1' ;
\ c template1
VACUUM FREEZE ;
UPDATE pg_database SET datallowconn = FALSE WHERE datname = 'template1'
Create Discourse database.
createdb -U mydatabaseuser discourse_production
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
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
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
Setup Rbenv.
cd
git clone git://github.com/sstephenson/rbenv.git .rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bash_profile
source ~/.bash_profile
Setup ssh for deployment with Mina.
ssh myexampleuser@example.com
mkdir -p apps/discourse
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
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. Here is the steps to setup Mina The Deployer.
Clone Discourse.
git clone git@github.com:discourse/discourse.git
cd discourse
Add mina to Gemfile.
# Gemfile
gem 'mina'
Generate mina config file inside Discource directory.
mina init
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 web server configuration.
# config/thin.yml
chdir : /home/myexampleuser/apps/discourse/current
environment : production
pid : /home/myexampleuser/apps/discourse/shared/pids/thin.pid
socket : /home/myexampleuser/apps/discourse/tmp/thin.sock
servers : 2
daemonize : true
onebyone : true
Sidekiq configuration.
# config/sidekiq.yml
production :
:concurrency : 5
:daemon : true
:logfile : /home/myexampleuser/apps/discourse/shared/log/sidekiq.log
:pidfile : /home/myexampleuser/apps/discourse/tmp/pids/sidekiq.pid
Mina configuration (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 , 'example.com'
set :deploy_to , '/home/myexampleuser/apps/discourse'
set :repository , 'git@github.com:discourse/discourse.git'
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"]
end
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'
end
end
end
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"
end
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"
end
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"
end
end
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"
end
desc "stop sidekiq"
task :stop => :environment do
queue "cd #{ deploy_to } / #{ current_path } / && bundle exec sidekiqctl stop /home/myexampleuser/apps/discourse/tmp/pids/sidekiq.pid"
end
desc "restart sidekiq"
task :restart => :environment do
invoke :'sidekiq:stop'
invoke :'sidekiq:start'
end
end
Run Mina Setup and deploy Command.
mina setup
mina deploy
login to server 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 = forum.example.com
login as root and copy Nginx configuration.
cd ~/apps/discourse/current
cp config/nginx.global.conf /etc/nginx/conf.d/
cp config/nginx.sample.conf /etc/nginx/conf.d/discourse.conf
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;
}
server_name forum.example.com;
Restart Nginx web server.
sudo service nginx restart
Exit from server, start Sidekiq and Thin
mina sidekiq:start
mina thin:start
Done! :)