Sunday, August 9, 2015

How Do I Deploy Discourse with Mina

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
  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 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
    
  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;
    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'
    
  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
    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
    
  12. Setup Server for Mina
    
    ssh [email protected]
    mkdir -p apps/discourse
    ssh-keyscan -H github.com >> ~/.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 [email protected]:discourse/discourse.git
    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/thin.pid
    socket: /home/myexampleuser/apps/discourse/tmp/thin.sock
    servers: 2
    daemonize: true
    onebyone: true
    


    Sidekiq config
    ---
    # 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 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, 'example.com'
    set :deploy_to, '/home/myexampleuser/apps/discourse'
    set :repository, '[email protected]: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
    
  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 = forum.example.com
    
  7. 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
    
  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;
    }
    
    server_name forum.example.com;
    
  9. Restart Nginx
    sudo service nginx restart
    
  10. Exit from VPS, start Sidekiq and Thin
    mina sidekiq:start
    mina thin:start
    
  11. Done! :)

No comments:

Post a Comment

© Railsmine