Update 1 [2016/09/30]: A section has been added to the end of the article for dealing with major FreeBSD upgrades.
Update 2 [2016/09/30]: A section has been added to the end of the article for upgrading current installation of Discourse to newer versions.
Update 3 [2016/09/30]: A section has been added to the end of the article for installing Discourse under Ruby version managers which is required for dealing with newer versions of Discourse since the current system-wide version of Ruby on FreeBSD is 2.2.5p319
.
Update 4 [2016/10/06]: I decided to get rid of Discourse on this blog for various reasons including negative feedback from my readers, performance issues, being a memory hog and not so easy on memory, difficult maintenance, dealing with building Ruby Gems which is a tedious task in case they fail to build and a bug that duplicates my posts and creates a new thread for each post which means it won’t show previous comments. Last but not least, in my estimation it’s too heavy for such a small task such as a comment system. As a result, this guide won’t be maintained anymore.
Well, when it comes to blog comment hosting services for static blogs, you will have a plethora of options such as SolidOpinion, Disqus, Livefyre, Google+ or Facebook comments, and many more. Unfortunately, such services has never been an option for me and I resisted them like forever. Yes, I’ve got one million reasons to believe and do so which demands another post of its own. So, I’ll avoid that argument for now.
This left me with two choices:
- Operate my blogs without the comment section as I did for years
- Running an open source self-host blog comment system such as HashOver, Isso, Juvia and talkatv
Since people asked me for a way to discuss their feedback on the website, this made the former choice a no go, anymore. So, in a search for the promised commenting system, I spent hours installing and trying every single FLOSS commenting system on GitHub. And everyone of them has had a big flaw that I could not tolerate. Finally, I came to the conclusion that I’m out of luck with that. Of course, I always had the option to write my own commenting system according to my own needs. As, I did with my own blog subscription system. But, due to the lack of time that was not an option either.
It happens that I randomly visit Coding Horror by Jeff Atwood the co-founder of Stack Overflow and Stack Exchange Network. I’ve always read the comments on Coding Horror but never had an urge to write a comment their. Since I’ve been desperately looking for a commenting system, this time the different look of its comment system catched my attention. Bingo! He wrote an open source discussion platform software named Discourse. Not necessarily a blog comment system, but could be used as one. It even supports the Farsi language and RTL out of the box which allows me to use it on my Farsi blog, too. In addition to that it supports multi-site which means I have to only run one instance for all my blogs. Just perfect!
Despite many nice feature it provides, it has a few rough edges, too. I was able to conquer some and some couldn’t, yet. But it did not stop me from integrating it into my Hexo-based blogs after two weeks of testing it. So, there it is, from now on both this blog and my Farsi blog are discussion aware :).
OK, the main issue that many people face when they want to install Discourse in a platform other than GNU/Linux, is they get hit in the face by the reading this line in the official documentation:
Why do you only officially support Docker?
Hosting Rails applications is complicated. Even if you already have Postgres, Redis and Ruby installed on your server, you still need to worry about running and monitoring your Sidekiq and Rails processes. Additionally, our Docker install comes bundled with a web-based GUI that makes upgrading to new versions of Discourse as easy as clicking a button.
Yes, I know Ruby and Rails are crap and deploying Ruby on Rails apps are pain in the Butt. Do not worry! This was the first struggle with Discourse that I had since this blog runs on FreeBSD. And, FreeBSD support for Docker is experimental, yet. Fortunately, I used to deploy GitLab instances on FreeBSD for three years which was also RoR before I migrated to Gogs which kicks butt, anyway! That made it easy to figure out a simple way to deploy Discourse without Docker on FreeBSD.
Table of Contents
Dependencies
Assuming you have ports-mgmt/pkg
(a.k.a pkgng) installed and initialized, we have to check for and install the missing Discourse dependencies:
$ pkg info | grep bundler
rubygem-bundler-1.11.2 Tool that manages gem dependencies for ruby applications
$ pkg info | grep gcc
gcc-4.8.5_2 GNU Compiler Collection 4.8
$ pkg info | grep gems
ruby22-gems-2.6.2 Package management framework for the Ruby language
$ pkg info | grep gifsicle
gifsicle-1.88 Manipulates GIF images and animations
$ pkg info | grep git
git-2.8.1 Distributed source code management tool
$ pkg info | grep gmake
gmake-4.1_2 GNU version of 'make' utility
$ pkg info | grep ImageMagick
ImageMagick-nox11-6.9.3.8_1,1 Image processing tools
$ pkg info | grep jpeg-turbo
jpeg-turbo-1.4.2 SIMD-accelerated JPEG codec which replaces libjpeg
$ pkg info | grep libxml2
libxml2-2.9.3 XML parser library for GNOME
$ pkg info | grep postgres
postgresql94-server-9.4.7 The most advanced open-source database available anywhere
$ pkg info | grep postgres
postgresql94-contrib-9.4.7 The contrib utilities from the PostgreSQL distribution
$ pkg info | grep redis
redis-3.0.7 Persistent key-value database with built-in net interface
$ pkg info | grep ruby
ruby-2.2.4,1 Object-oriented interpreted scripting language
$ pkg info | grep sudo
sudo-1.8.16 Allow others to run commands as root
In my case the only missing dependencies were graphics/ImageMagick
and graphics/gifsicle
. So if you want to install from source using Ports:
$ cd /usr/ports/graphics/ImageMagick-nox11/
$ make config-recursive
$ make install clean
$ cd /usr/ports/graphics/gifsicle/
$ make config-recursive
$ make install clean
Or, alternatively install the binaries using pkgng:
$ pkg install graphics/ImageMagick-nox11 graphics/gifsicle
Note that I choose graphics/ImageMagick-nox11 over graphics/ImageMagick since it pulls in less dependency.
Database
OK, after installing the required dependencies, it’s time to initialize the database by creating a user name and a password. In addition to that we have to enable the required PostgreSQL extensions.
By default, Discourse chooses discourse
for both database name and user name. I’ll choose discourse
user name and discourse_production
for database name. Let’s assume that I want discuss.babaei.net and discuss.fa.babaei.net share the same Discourse instance.
If you are planing to run only one website / blog on Discourse:
$ sudo -u pgsql psql -d template1
template1=# CREATE USER discourse CREATEDB;
template1=# CREATE DATABASE discourse_production WITH ENCODING='UTF8' OWNER discourse;
template1=# \l
template1=# \c discourse_production
discourse_production=# CREATE EXTENSION hstore;
discourse_production=# CREATE EXTENSION pg_trgm;
If you plan for a multi-site install, in addition to the above commands:
discourse_production=# CREATE DATABASE discourse_babaei_net_production WITH ENCODING='UTF8' OWNER discourse;
discourse_production=# CREATE DATABASE discourse_fa_babaei_net_production WITH ENCODING='UTF8' OWNER discourse;
discourse_production=# \l
discourse_production=# \c discourse_babaei_net_production
discourse_babaei_net_production=# CREATE EXTENSION hstore;
discourse_babaei_net_production=# CREATE EXTENSION pg_trgm;
discourse_babaei_net_production=# \c discourse_fa_babaei_net_production
discourse_fa_babaei_net_production=# CREATE EXTENSION hstore;
discourse_fa_babaei_net_production=# CREATE EXTENSION pg_trgm;
Finally exit PostgreSQL command line by issuing: \q
.
One more thing: it’s possible to protect the user login with a password. In that case, instead of:
template1=# CREATE USER discourse CREATEDB;
Create the user using this command:
template1=# CREATE ROLE discourse LOGIN ENCRYPTED PASSWORD '${SECRET_PASSWORD}' NOINHERIT VALID UNTIL 'infinity';
Obviously instead of ${SECRET_PASSWORD}
you must put your own password. Since PostgreSQL by default do not listen for external connections and only accepts local requests, you may find it unnecessary to password-protect the user login unless you are running Discourse and PostgreSQL on different machines.
You can check whether your PostgreSQL instance refuses external connections or not by taking a look at /usr/local/pgsql/data/pg_hba.conf
:
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
#local replication pgsql trust
#host replication pgsql 127.0.0.1/32 trust
#host replication pgsql ::1/128 trust
The above default settings allow local connectons only.
System User and Group
Now that we’ve initialized the database, we have to create the Discourse system user name and group. Note that the user name must be the same as the user name you chose at the previous step. We chose discourse
user name at the time of database creation. We’ll also go with /home/discourse
as Discourse home directory. So:
$ pw addgroup discourse $ pw adduser discourse -g discourse -m -d /home/discourse -c “Discourse” $ pw usermod discourse -G redis
So, We did create the user and its group. Moreover, we add the user to redis
group.
Source Code
Now that we have the Discourse user added to the system:
$ cd /home/discourse/
$ sudo -u discourse -H git clone https://github.com/discourse/discourse.git
After cloning Discourse source code we have to find out the latest stable tag by issuing:
$ cd /home/discourse/discourse/
$ sudo -u discourse -H git tag -l
The output is something like this:
latest-release
v0.8.0
v0.8.1
v0.8.2
v0.8.3
v0.8.4
v0.8.5
v0.8.6
v0.8.7
v0.8.8
v0.8.9
v0.9.0
v0.9.1
v0.9.2
v0.9.2.5
v0.9.2.6
v0.9.3
v0.9.3.5
v0.9.4
v0.9.5
v0.9.5.1
v0.9.5.2
v0.9.6
v0.9.6.1
v0.9.6.2
v0.9.6.3
v0.9.6.4
v0.9.7
v0.9.7.1
v0.9.7.2
v0.9.7.3
v0.9.7.4
v0.9.7.5
v0.9.7.6
v0.9.7.7
v0.9.7.8
v0.9.7.9
v0.9.8
v0.9.8.1
v0.9.8.10
v0.9.8.11
v0.9.8.2
v0.9.8.3
v0.9.8.4
v0.9.8.5
v0.9.8.6
v0.9.8.7
v0.9.8.8
v0.9.8.9
v0.9.9
v0.9.9.1
v0.9.9.10
v0.9.9.11
v0.9.9.12
v0.9.9.13
v0.9.9.14
v0.9.9.15
v0.9.9.16
v0.9.9.17
v0.9.9.18
v0.9.9.2
v0.9.9.3
v0.9.9.4
v0.9.9.5
v0.9.9.6
v0.9.9.7
v0.9.9.8
v0.9.9.9
v1.0.0
v1.0.1
v1.0.2
v1.0.3
v1.0.4
v1.1.0
v1.1.0.beta1
v1.1.0.beta2
v1.1.0.beta3
v1.1.0.beta4
v1.1.0.beta5
v1.1.0.beta6
v1.1.0.beta6b
v1.1.0.beta7
v1.1.0.beta8
v1.1.1
v1.1.2
v1.1.3
v1.2.0
v1.2.0.beta1
v1.2.0.beta2
v1.2.0.beta3
v1.2.0.beta4
v1.2.0.beta5
v1.2.0.beta6
v1.2.0.beta7
v1.2.0.beta8
v1.2.0.beta9
v1.2.1
v1.2.2
v1.2.3
v1.2.4
v1.3.0
v1.3.0.beta1
v1.3.0.beta10
v1.3.0.beta11
v1.3.0.beta2
v1.3.0.beta3
v1.3.0.beta4
v1.3.0.beta5
v1.3.0.beta6
v1.3.0.beta7
v1.3.0.beta8
v1.3.0.beta9
v1.3.1
v1.3.2
v1.3.3
v1.3.4
v1.3.5
v1.4.0
v1.4.0.beta1
v1.4.0.beta10
v1.4.0.beta11
v1.4.0.beta12
v1.4.0.beta2
v1.4.0.beta3
v1.4.0.beta4
v1.4.0.beta5
v1.4.0.beta6
v1.4.0.beta7
v1.4.0.beta8
v1.4.0.beta9
v1.4.1
v1.4.2
v1.4.3
v1.4.4
v1.4.5
v1.4.6
v1.4.7
v1.5.0
v1.5.0.beta1
v1.5.0.beta10
v1.5.0.beta11
v1.5.0.beta12
v1.5.0.beta13
v1.5.0.beta13b
v1.5.0.beta14
v1.5.0.beta2
v1.5.0.beta3
v1.5.0.beta4
v1.5.0.beta5
v1.5.0.beta6
v1.5.0.beta7
v1.5.0.beta8
v1.5.0.beta9
v1.5.1
v1.6.0.beta1
v1.6.0.beta2
In the above output, the latest stable release is v1.5.1
while latest-release
tag is the latest beta, stable or whatever it is. So, I’ll checkout v1.5.1
tag by:
$ sudo -u discourse -H git checkout tags/v1.5.1
Configuration Files
Most RoR applications have a section named production
in <project-root>/config/database.yml
file.
You’ll only find the following comments inside config/database.yml
for Discourse:
|
|
Discourse is a bit different. It has some defaults values which you will be able to override. The default configuration resides inside config/discourse_defaults.conf
:
|
|
As the first line in that file suggests you must avoid touching this file. Instead create an empty file inside the same directory at config/discourse.conf
which is /home/discourse/discourse/config/discourse.conf
in our case and put the desired configuration there:
|
|
Note that some of the above settings are imaginary and is provided as an example. So, they might not work for you and you should adjust them according to your environment, or do not override the default ones at all.
If you are running a multi-site setup you have to create another file named config/multisite.yml
. First take a look at config/multisite.yml.production-sample
to get an idea of what its contents look like:
|
|
So for our multi-site example I’ll create the /home/discourse/discourse/config/multisite.yml
with the following content:
|
|
Install Gems
$ cd /home/discourse/discourse/
$ sudo -u discourse -H bundle install --deployment --without test --without development
Grab a cup of coffee! This may take a while.
Database Migration
No matter if this is the first time you install Discourse or you are upgrading, this is a necessary part of the process.
For single-site installations:
$ cd /home/discourse/discourse/
$ sudo -u discourse -H RAILS_ENV=production bundle exec rake db:migrate
For multi-site installations:
$ cd /home/discourse/discourse/
$ sudo -u discourse -H RAILS_ENV='production' bundle exec rake multisite:migrate
Precompile Assets
$ cd /home/discourse/discourse/
$ sudo -u discourse -H RAILS_ENV=production bundle exec rake assets:precompile
This one should take some time to complete.
Startup Script
Congratulations! If you made it so far you’ve probably setup Discourse successfully. But, before we run the Discourse application server let’s write a small script to run it properly in a simple way.
First, let’s create the required directories, and set the current permissions:
$ sudo -u discourse -H mkdir -p /home/discourse/cron/
$ sudo -u discourse -H mkdir -p /home/discourse/log/
$ chmod -R g-rxw,o-rxw /home/discourse/cron
$ chmod -R g-rxw,o-rxw /home/discourse/log
$ chown -R www:www /home/discourse/log
Then, to write the script in your default editor (of course you can choose another editor by replacing $EDITOR environment variable in the following command, directly with your preferred editor executable’s name):
$ sudo -u discourse -H $EDITOR /home/discourse/cron/server.sh
Now copy paste the following and be wary not to break the lines inside your editor:
|
|
I chose to go with Thin and Unix domain sockets. That -s8
argument creates eight Unix socket domain connections. So, change that according to your needs.
Alternatively it’s possible to use TCP connections instead of Unix domain sockets (consider that Unix domain sockets can achieve better throughput than the TCP/IP loopback). To run Thin server and listen for connections on port 11011
, replace the last line of the script with:
$ sudo -u discourse -H RAILS_ENV=production RUBY_GC_MALLOC_LIMIT=90000000 \
bundle exec thin start -p 11011 > /home/discourse/discourse/log/thin.log 2>&1&
To serve the application on default Rails server instead of Thin (definitely a bad decision since it’s slower), replace the last line of the script with:
$ sudo -u discourse -H RAILS_ENV='production' RUBY_GC_MALLOC_LIMIT=90000000 \
bundle exec rails server /home/discourse/discourse/log/rails_server.log
By the way, you can read about what’s the big deal about that bloody RUBY_GC_MALLOC_LIMIT=90000000 here.
Before running the script, set it executable for all users:
$ chmod a+x /home/discourse/cron/server.sh
And then run the script if you wish:
$ /home/discourse/cron/server.sh
To check if your Sidekiq instance and Thin server started successfully or not:
$ ps auxw | grep ruby
discourse 2573 0.0 12.9 1163352 178056 - S Mon01AM 128:25.44 ruby22: sidekiq 4.0.2 discourse [0 of 25 busy] (ruby22)
discourse 2576 0.0 12.9 987464 177624 - I Mon01AM 6:58.57 ruby22: thin server (/home/discourse/discourse/tmp/sockets/thin.0.sock) (ruby22)
discourse 2579 0.0 12.6 966856 187356 - I Mon01AM 5:32.62 ruby22: thin server (/home/discourse/discourse/tmp/sockets/thin.1.sock) (ruby22)
discourse 2584 0.0 11.8 986264 182331 - I Mon01AM 6:38.12 ruby22: thin server (/home/discourse/discourse/tmp/sockets/thin.2.sock) (ruby22)
discourse 2585 0.0 13.1 997361 177239 - I Mon01AM 5:59.31 ruby22: thin server (/home/discourse/discourse/tmp/sockets/thin.3.sock) (ruby22)
discourse 2587 0.0 13.6 983232 183451 - I Mon01AM 5:49.12 ruby22: thin server (/home/discourse/discourse/tmp/sockets/thin.4.sock) (ruby22)
discourse 2589 0.0 13.6 977334 182345 - I Mon01AM 5:17.11 ruby22: thin server (/home/discourse/discourse/tmp/sockets/thin.5.sock) (ruby22)
discourse 2590 0.0 12.9 983232 193454 - I Mon01AM 6:33.88 ruby22: thin server (/home/discourse/discourse/tmp/sockets/thin.6.sock) (ruby22)
discourse 2591 0.0 13.1 983333 187443 - I Mon01AM 7:12.01 ruby22: thin server (/home/discourse/discourse/tmp/sockets/thin.7.sock) (ruby22)
To stop your Sidekiq or Thin instances I highly recommend sending SIGTERM
instead of SIGKILL
to their processes and give them some time to clean-up gracefully:
$ kill -SIGTERM 2576
If you are looking for an easier way to stop and monitor your Thin and Sidekiq instances, sysutils/htop
is an viable option.
Cron Job
Well, I am sure we cannot afford to run the script manually after each reboot, so we have to set it up as a cron job:
$ crontab -e -u root
When your default editor appears, add this to the end of your cron jobs:
|
|
Now to check whether your cron job has been added successfully or not, enter the following command:
$ crontab -l
For your cron job to take effect:
$ service cron restart
Now, after each reboot it will start automatically.
Nginx Configuration
I took the example Nginx configuration from config/nginx.sample.conf
and adapt it to our example:
|
|
Troubleshooting
So, that’s it. If you did setup everything right, you must see the Discourse home page by entering e.g. discuss.babaei.net or discuss.fa.babaei.net inside your browser. Otherwise, the first place to check are the log files that reside inside /home/discourse/log/
and /home/discourse/discourse/log/
. If you still do not have any clue why it’s not working, make sure to double check that you did follow the tutorial correctly. Other than that, you are always welcome to discuss it in the comments section below.
Major FreeBSD Upgrades
Generally, after each major upgrade to FreeBSD there are version bumps and ABI changes to the shared libraries on the system which which will break most third-party applications. After a major version upgrade, all native gems need to be upgraded. So in order to survive the upgrade, simply run:
$ cd /home/discourse/discourse/
$ rm -rf vendor/bundle/ruby
$ gem pristine --all
$ sudo -u discourse -H bundle install --deployment --without test --without development
Upgrading Discourse
1. First kill Sidekiq and Thin servers:
$ ps | grep discourse | grep -v grep | awk '{print $1}' | xargs kill -9
2. Then, take a backup from all your Discourse databases. In my case:
$ mkdir -p ~/discourse-backups/
$ sudo -u pgsql pg_dump discourse_babaei_net_production \
> ~/discourse-backups/discourse_babaei_net_production.sql
$ sudo -u pgsql pg_dump discourse_fa_babaei_net_production \
> ~/discourse-backups/discourse_fa_babaei_net_production.sql
$ sudo -u pgsql pg_dump discourse_production \
> ~/discourse-backups/discourse_production.sql
3. Update the local Discourse git repository with the latest changes from its official GitHub repository:
$ cd /home/discourse/discourse/
$ sudo -u discourse -g discourse -H git pull
4. Now, let’s switch to desired version of Discourse:
$ sudo -u discourse -g discourse -H git status
HEAD detached at v1.5.1
nothing to commit, working tree clean
$ sudo -u discourse -g discourse -H git reset --hard
HEAD is now at 47e9321 Version bump to v1.5.1
$ sudo -u discourse -g discourse -H git tag -l
The last command outputs a lengthy list of git tags as we saw earlier. Choose the latest stable tag or the one you desire and switch to the new tag (see the following note):
$ sudo -u discourse -g discourse -H git checkout tags/v1.5.4
Previous HEAD position was 47e9321... Version bump to v1.5.1
HEAD is now at c8081af... Version bump to v1.5.4
Note: At the time of writing this note, the latest stable tag is v1.6.4
. Bear in mind that the minimum required version of Ruby for this version is 2.3.x
. On the other hand, FreeBSD uses Ruby 2.2.x
by default. So, either stick to 1.5.x
or install a Ruby version manager to manage several Ruby binaries without dependency breaks. For the sake of simplicity, I’m not going to cover Ruby version managers in this section. Instead, a dedicated section on Ruby version managers can be found at the of the article.
5. Install the new gems:
$ sudo -u discourse -g discourse -H bundle install \
--deployment --without test --without development
Note: Installing or upgrading to 1.5.x
will fail at this stage on FreeBSD 11.0-RELEASE
due to build errors from libv8. What worked for me is this:
$ pkg install v8
$ sudo -u discourse -g discourse -H bundle config build.libv8 --with-system-v8
$ sudo -u discourse -g discourse -H bundle install \
--deployment --without test --without development
After that proceed to the next step.
6. It’s time to migrate the database. For a single instant installation of Discourse:
$ sudo -u discourse -g discourse -H RAILS_ENV='production' \
bundle exec rake db:migrate
If you are running a multi-site instance, run the following command instead of the previous one:
$ sudo -u discourse -g discourse -H RAILS_ENV='production' \
bundle exec rake multisite:migrate
7. Precompile the new assets:
$ sudo -u discourse -g discourse -H RAILS_ENV=production \
bundle exec rake assets:precompile
8. Finally run the script we wrote earlier to start Discourse:
$ sh /home/discourse/cron/server.sh &
9. Done! Check if everything is working fine through your browser.
Things went south?
Do not worry!
1. Restore the database (this can be safely skipped for patch versions, e.g. reverting 1.5.4 to 1.5.1, as they usually won’t introduce any changes to the database structure, unless your actual data is corrupted):
$ sudo -u pgsql psql -d template1
template1=# DROP DATABASE discourse_production;
template1=# DROP DATABASE discourse_babaei_net_production;
template1=# DROP DATABASE discourse_fa_babaei_net_production;
template1=# CREATE DATABASE discourse_production WITH ENCODING='UTF8' OWNER discourse;
template1=# CREATE DATABASE discourse_babaei_net_production WITH ENCODING='UTF8' OWNER discourse;
template1=# CREATE DATABASE discourse_fa_babaei_net_production WITH ENCODING='UTF8' OWNER discourse;
template1=# \c discourse_production
discourse_production=# CREATE EXTENSION hstore;
discourse_production=# CREATE EXTENSION pg_trgm;
discourse_production=# \c discourse_babaei_net_production
discourse_babaei_net_production=# CREATE EXTENSION hstore;
discourse_babaei_net_production=# CREATE EXTENSION pg_trgm;
discourse_babaei_net_production=# \c discourse_fa_babaei_net_production
discourse_fa_babaei_net_production=# CREATE EXTENSION hstore;
discourse_fa_babaei_net_production=# CREATE EXTENSION pg_trgm;
discourse_fa_babaei_net_production=# \q
$ sudo -u pgsql psql discourse_babaei_net_production \
< ~/discourse-backups/discourse_babaei_net_production.sql
$ sudo -u pgsql psql discourse_fa_babaei_net_production \
< ~/discourse-backups/discourse_fa_babaei_net_production.sql
$ sudo -u pgsql psql discourse_production \
< ~/discourse-backups/discourse_production.sql
2. Revert back to the old version:
$ sudo -u discourse -g discourse -H git checkout tags/v1.5.1
3. Run the script we wrote earlier to start Discourse:
$ sh /home/discourse/cron/server.sh &
4. Done! Check if everything is working fine through your browser.
Ruby Version Manager
Ruby version managers are designed to manage multiple installations of Ruby at the same time on the same system. There are quite a few Ruby version managers but the most notable ones are RVM, rbenv and chruby.
Instead of RVM or rbenv I’ll go with chruby (there are plenty of great tutorials on the topic out there. Just search for “FreeBSD RVM”, “FreeBSD rbenv” or whatever):
$ cd /usr/ports/devel/ruby-build/
[ ] RBENV Install rbenv for installation support
$ make config-recursive
$ make install clean
$ cd /usr/ports/devel/chruby/
$ make config-recursive
$ make install clean
Or if you are using pkgng:
$ pkg install ruby-build chruby
Check whether you have Bash installed or not since it’s required by chruby (chruby installation must automatically pulls in shells/bash
):
$ pkg info bash
It is recommended to run Ruby version managers as users instead of a system-wide configuration. So:
$ sudo -u discourse -g discourse -H bash
$ export PS1="(DISCOURSE) $PS1"
This will drop us in a bash command prompt as discourse
user. Now, we have to import chruby environment variables to our shell by running:
(DISCOURSE) $ source /usr/local/share/chruby/chruby.sh
or (yes that is a dot and a space):
(DISCOURSE) $ . /usr/local/share/chruby/chruby.sh
To make this permanent, add the following lines to ~/.bashrc
(equals to /home/discourse/.bashrc
in our setup):
# chruby
source /usr/local/share/chruby/chruby.sh
OK, let’s find out which version of Ruby is the latest stable 2.3.x
:
(DISCOURSE) $ ruby-build --definitions | grep -w '2.3'
2.2.3
2.3.0-dev
2.3.0-preview1
2.3.0-preview2
2.3.0
2.3.1
rbx-2.2.3
rbx-2.3.0
At the moment 2.3.1
is the latest stable one. So, to install Ruby 2.3.1
(this takes some time):
(DISCOURSE) $ CC=clang RUBY_CONFIGURE_OPTS=--with-opt-dir=/usr/local \
ruby-build 2.3.1 ~/.rubies/ruby-2.3.1
Downloading ruby-2.3.1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.bz2
Installing ruby-2.3.1...
Installed ruby-2.3.1 to /home/discourse/.rubies/ruby-2.3.1
Note 1: I had lang/gcc-4.8.5_2
installed on my system which caused a lot of trouble for me. Remove it before you install the new Ruby, or bundler spits out these errors while building native extensions such as libv8:
current directory:
/usr/home/discourse/discourse/vendor/bundle/ruby/2.3.0/gems/unf_ext-0.0.7.1/ext/unf_ext
make "DESTDIR="
compiling unf.cc
g++: error: unrecognized command line option '-Wshorten-64-to-32'
g++: error: unrecognized command line option '-Wdivision-by-zero'
g++: error: unrecognized command line option '-Wextra-tokens'
*** Error code 1
This happens because when we build Ruby it mix up compilers.
Note 2: Looks like the new version of Discourse (1.6.4
) pulls in a new dependency called rmmseg-cpp
which requires gcc (I know! I hate Ruby, Rails and friends, too). Remove gcc, proceed with the installation. When the bundle install failed, reinstall gcc again (it can stay till your next Ruby installation for Discourse) and resume the installation instructions.
After successful installation of the new Ruby, let’s see if it gets picked up by chruby. After installing new Rubies, you must restart the shell before chruby can recognize them:
(DISCOURSE) $ exit
$ sudo -u discourse -g discourse -H bash
$ export PS1="(DISCOURSE) $PS1"
(DISCOURSE) $ chruby
ruby-2.3.1
Time to choose the new Ruby:
(DISCOURSE) $ chruby ruby-2.3.1
(DISCOURSE) $ ruby --version
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-freebsd11.0]
To set default Ruby permanently, put the following line inside ~/.bashrc
:
# Default Ruby Version
chruby ruby-2.3.1
So, at the end your ~/.bashrc
must look like this (the order is important):
|
|
The last step includes installing bundler inside the new environment for Discourse installation and update:
(DISCOURSE) $ gem install bundler
Before proceeding to Discourse installation or upgrade, I highly recommend to verify the new Ruby environment:
(DISCOURSE) $ echo $PATH
/home/discourse/.gem/ruby/2.3.1/bin:/home/discourse/.rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/bin:/home/discourse/.rubies/ruby-2.3.1/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin
(DISCOURSE) $ which ruby
/home/discourse/.rubies/ruby-2.3.1/bin/ruby
(DISCOURSE) $ which bundle
/home/discourse/.gem/ruby/2.3.1/bin/bundle
(DISCOURSE) $ which gem
/home/discourse/.rubies/ruby-2.3.1/bin/gem
(DISCOURSE) $ cd ~/discourse
(DISCOURSE) $ bundle env
Environment
Bundler 1.13.2
Rubygems 2.6.4
Ruby 2.2.5p319 (2016-04-26 revision 54774) [amd64-freebsd11]
GEM_HOME /home/discourse/.gem/ruby/2.3.1
GEM_PATH /home/discourse/.gem/ruby/2.3.1:/home/discourse/.rubies/ruby-2.3.1/lib/ruby/gems/2.3.0
Git 2.9.2
It is very important that the new Ruby path appears before any other path in the $PATH
variable. And, for ruby
, gem
and bundler
executables, the path must refer to the corresponding version inside /home/discourse/
.
As you can see my Ruby version is wrong. For me the easy fix was to reboot the system. After that eveything was fine:
(DISCOURSE) $ cd ~/discourse
(DISCOURSE) $ bundle env
Environment
Bundler 1.13.2
Rubygems 2.5.1
Ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-freebsd11.0]
GEM_HOME /home/discourse/.gem/ruby/2.3.1
GEM_PATH /home/discourse/.gem/ruby/2.3.1:/home/discourse/.rubies/ruby-2.3.1/lib/ruby/gems/2.3.0
Git 2.9.2
OK, let’s try the upgrade process to v1.6.4
at once (note that we got rid of sudo
since we are already running bash
under discourse
user, hence, any process that starts from this command line will run as user discourse
):
(DISCOURSE) $ ps | grep discourse | grep -v grep | awk '{print $1}' | xargs kill -9
(DISCOURSE) $ ps | grep sidekiq | grep -v grep | awk '{print $1}' | xargs kill -9
(DISCOURSE) $ ps | grep thin | grep -v grep | awk '{print $1}' | xargs kill -9
(DISCOURSE) $ mkdir -p ~/db-backups/
(DISCOURSE) $ sudo -u pgsql pg_dump discourse_babaei_net_production \
> ~/db-backups/discourse_babaei_net_production.sql
(DISCOURSE) $ sudo -u pgsql pg_dump discourse_fa_babaei_net_production \
> ~/db-backups/discourse_fa_babaei_net_production.sql
(DISCOURSE) $ sudo -u pgsql pg_dump discourse_production \
> ~/db-backups/discourse_production.sql
(DISCOURSE) $ cd ~/discourse/
(DISCOURSE) $ git pull
(DISCOURSE) $ git status
HEAD detached at v1.5.4
nothing to commit, working tree clean
(DISCOURSE) $ git reset --hard
HEAD is now at c8081af Version bump to v1.5.4
(DISCOURSE) $ git tag -l
(DISCOURSE) $ git checkout tags/v1.6.4
Previous HEAD position was c8081af... Version bump to v1.5.4
HEAD is now at 4673295... Version bump to v1.6.4
(DISCOURSE) $ bundle install --deployment --without test --without development
# single instance installations
(DISCOURSE) $ RAILS_ENV='production' bundle exec rake db:migrate
# multi-site setup
(DISCOURSE) $ RAILS_ENV='production' bundle exec rake multisite:migrate
(DISCOURSE) $ RAILS_ENV=production bundle exec rake assets:precompile
Modify the shebang line of /home/discourse/cron/server.sh
script and change it from #!/bin/sh
to #!/usr/bin/env bash
:
|
|
Run the discourse server and check your discourse installation to see if everything works fine:
(DISCOURSE) $ /home/discourse/cron/server.sh &
So far, so good. Now we have to remove the cron job we previously set up for root
user:
$ crontab -e -u root
Remove these lines:
# Discourse
# At Boot
@reboot /home/discourse/cron/server.sh
Then save and exit. Enter the following command to see if it has been removed:
$ crontab -l
Now, we have to set up the cron job for discourse
user:
$ crontab -e -u discourse
Your list of cron jobs must be empty. Add the following lines (read more on cron jobs):
|
|
Now to see whether your cron job has been added successfully or not, enter the following command:
$ crontab -l -u discourse
Reboot your system to see if it start ups automatically.
See also
- WebRTC IP Leak Demonstration
- How to disable HP Proliant ML350p Gen8 P420i RAID controller, enable HBA mode (a.k.a. pass-through), and perform a FreeBSD root on ZFS installation
- A quick workaround for Unreal Engine Modeling Tools Editor Mode plugin not showing up on Linux and macOS
- Host Unreal Engine 4 projects on Microsoft Azure DevOPS with unlimited cost-free Git LFS quota