Hero Image
- Sebastian Klus

Rocket.Chat 3.0.3 on Ubuntu 18.04

Rocket.Chat is an open-source communication platform, something similar to Slack maybe. I opted for the selfhosted community version and run it on a Ubuntu 18.04 VPS together with Node.js, MongoDB and Nginx (including Let's Encrypt SSL certificate).

This tutorial is quite long, so in case you need to jump forward:

Versions

I installed Rocket.Chat with the following versions:

  • Rocket.Chat: 3.0.3
  • Node.js: 12.14.0
  • MongoDB: 4.0
  • Nginx: ###

Installation

I puzzled together information from several sites (see sources [below]) as I had some trouble with the configuration of MongoDB, when trying to start the Rocket.Chat server. So, here we go:

Nginx webserver

Installing Nginx is quite straigth forward:

sudo apt-get update
sudo apt-get install nginx

Normally, installation should not throw any errors, so right afterwards you can check the status of the server:

sudo systemctl status nginx

Among some other text, the following should show up (third line probably):

Active: active (running) since Sun 2020-03-12 14:32:58 UTC; 1min ago

If everything is running, you should be able to access your webserver http://SERVER_IP_ADDRESS and see the Nginx test page. This is also a good time to set up a new DNS record with a (sub-) domain, in case you are going to access your Rocket.Chat through it because it always takes some time until DNS records are internationally updated. Ideally, you did it already the day before, because then the next step should run without any major issues or delays.

Let's Encrypt SSL certificate

Let's Encrypt is a certificate authority that is run by the Internet Security Research Group (ISRG), which allows you to issue SSL certificates for your domains. These certificates are recognized by practically all browsers and you do not have to pay anything (unless you wish to make a donnation).

The process is automized by Certbot; to install it, just type:

sudo apt-get install certbot

The ISRG recommends to generate your own encryption parameters (they are called Diffie-Hellman parameters):

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

You are going to use the newly created dhparam.pem file later on, when configuring Nginx and requiring the use of SSL for you connection to Rocket.Chat.

Certbot offers a couple of ways to confirm that the domain you are issuing the SSL certificate for is really yours. One way is to allow the webserver to temporarily save a file in a specific directory of your webserver and make the certification authority (CA) access it. This way, the CA knows that the webserver is in fact under your control.

Let's see: first we are going to create the directory where Certbot is going to store the temporary file and make it accessible for the Nginx webserver:

sudo mkdir -p /var/lib/letsencrypt/.well-known
sudo chgrop www-data /var/lib/letsencrypt
sudo chmod g+s /var/lib/letsencrypt

Then we are going to create two new files with some initial SSL configuration for the Nginx webserver. The first file is letsencrypt.conf; you can create it from the command line with sudo vi /etc/nginx/snippets/letsencrypt.conf.

Type (or better copy) the following text into letsencrypt.conf:

location ^~ /.well-known/acme-challenge/ {
  allow all;
  root /var/lib/letsencrypt/;
  default_type "text/plain";
  try_files $uri =404;
}

The second file we need is ssl.conf; create it with sudo vi /etc/nginx/snippets/ssl.conf and add the following content:

ssl_dhparam /etc/ssl/certs/dhparam.pem;

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;

ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 30s;

add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;

You may have noticed that the file calls in the first line for the DH parameters we created previously. The rest of the parameters are configuration recommendations from Mozilla's SSL Configuration Generator.

Now, we are going to create the server configuration block. I will be using chat.example.com as domain for Rocket.Chat, so just replace chat.example.com by your own domain whereever you see it.

Create the new file with sudo vi /etc/nginx/sites-available/chat.example.com.conf and add the following content:

server {
  listen 80;
  server_name chat.example.com

  include snippets/letsencrypt.conf
}

To enable the domain and this server block, you need to create a symbolic link from this file to the sites-enabled directory and restart the Nginx webserver:

sudo ln -s /etc/nginx/sites-available/chat.example.com.conf /etc/nginx/sites-enabled/
sudo systemctl restart nginx
sudo systemctl status nginx

The last command should show you that the webserver is up and running again. If some error occurs, check your spelling in the configuration files and restart the webserver again.

Now we are going to use Certbot to create the new SSL certificate. Remember to replace the e-mail address email@example.com and the domain chat.example.comby your own information.

sudo certbot certonly --agree-tos --email email@example.com --webroot -w /var/lib/letsencrypt/ -d chat.example.com

There will be a couple of more questions and on-screen messages. Most importantly, at the end the following should show up:

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
  /etc/letsencrypt/live/example.com/fullchain.pem
  Your key file has been saved at:
  /etc/letsencrypt/live/example.com/privkey.pem
  Your cert will expire on 2018-07-28. To obtain a new or tweaked
  version of this certificate in the future, simply run certbot
  again. To non-interactively renew *all* of your certificates, run
  "certbot renew"

Plus some other information. Read it, take note of it and try to understand it. Do not just copy & paste everything from here. This applies by the way to all the steps stated here.

If that went well and you now have the SSL certificates, you can modify the configuration file chat.example.com.conf of your server as follows:

server {
  listen 80;
  server_name chat.example.com;

  include snippets/letsencrypt.conf;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  server_name chat.example.com;

  ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/chat.example.com/chain.pem;
  include snippets/ssl.conf;
  include snippets/letsencrypt.conf;

  # We are going to add some other code here later on
}

This basically redirects any user that just uses http to the same address, but at https, so that any communication with your server is encrypted.

Again, reload the webserver so that the updated configuration takes effect:

sudo systemctl reload nginx

If you read carefully above, the Let's Encrypt SSL certificates are valid for three months. So, we are going to make sure that they get renewed automatically and that the webserver is reloaded after each renewal. For that, just add --renew-hook "systemctl reload nginx" to the end of the only existing line in the certbot file. This file already exists; just edit it with sudo vi /etc/cron.d/certbot. The updated line should look like this:

0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook "systemctl reload nginx"

Do a test run to make sure that the renewal routine works properly:

sudo certbot renew --dry-run

This will not actually renew your (just recently created) SSL certificate, but will only simulate the renewal process. If no errors come up, everything is running correctly.

MongoDB

Rocket.Chat relies on MongoDB as its database backend and it is recommended to install the current version from MongoDB, instead of using the version in Ubuntu's default repositories.

In order to do that, one must add the public keys from the MongoDB repositories to Ubuntu's key storage:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4
sudo add-apt-repository 'deb [arch=amd64] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse'

After that, the local repositories must be updated and then, MongoDB can be installed normally:

sudo apt-get update
sudo apt-get install mongodb-org

Once installed, MongoDB must be started and linked into the list of services, so that MongoDB is started automatically at startup:

sudo systemctl start mongodb
sudo systemctl enable mongodb

What configuration of MongoDB is concerned, we will need to enable at least one replica set. A replica set is a set of MongoDB databases that keeps a set of data in sync. The idea behind is that you can distribute your data throughout different locations for redundancy. But you do not have to: we are going to set up just one set in just one single location. For that, we need to modify MongoDB's main configuration file /etc/mongod.conf. Access it with the following command:

sudo vi /etc/mongod.conf

If you just installed MongoDB and are working with the standard configuration, approximately half way down the file there is a replication section. Right there, add the following lines:

replication:
  replSetName: "rs01"

Save and close and then restart the MongoDB service:

sudo systemctl restart mongod

Now, enter the MongoDB command line; just enter:

mongo

The command line will show a couple of lines about the version of the database and then show the command line of MongoDB. There, enter the following command to start the replica set:

rs.initiate()

The confirmation of the initiation of the replica set will look more or less like that:

{
    "operationTime" : Timestamp(1562351876, 1),
    "ok" : 0,
    "errmsg" : "already initialized",
    "code" : 23,
    "codeName" : "AlreadyInitialized",
    "$clusterTime" : {
        "clusterTime" : Timestamp(1562351876, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}

A line shows up at the end, where you can set a second or another replica set; just type exit to leave the MongoDB command line. MongoDB is now up and running, which leaves us to the final installation and configuration of Node.js and Rocket.Chat.

Rocket.Chat

Rocket.Chat requires Node.js, so we start with the installation of the required components:

sudo apt-get install nodejs npm build-essential curl software-properties-common graphicsmagick

Then, we need to install the corresponding modules and tell Node.js which version to simulate.

sudo npm install -g inherits n
sudo n 12.14.0

For Rocket.Chat 3.0.3 (which we use in this tutorial), Node.js 12.14.0 is required, but if you are going to install another version of Rocket.Chat, check out the corresponding version of Node.js here and change the version number in the previous command accordingly.

Now we are going to create a separate system user that Rocket.Chat will be running under. The following commands will create the user rocket, add it to the group www-data and restrict the access to the home directory of the rocket user:

sudo useradd -m -U -r -d /opt/rocket rocket
sudo usermod -a -G rocket www-data
sudo chmod 750 /opt/rocket

Next, we are going to download Rocket.Chat directly under the user we just created (rocket) and run a first test of the Rocket.Chat server. So, first we need to change to the new user account:

sudo su - rocket

To download the current version of Rocket.Chat, enter:

curl -L https://releases.rocket.chat/latest/download -o rocket.chat.tgz

Once the download is complete, we need to extract the compressed file and change the name of the standard directory where all the files of Rocket.Chat are saved in by default:

tar zxf rocket.chat.tgz
mv bundle Rocket.Chat

Now we are going to change into the Rocket.Chat/programs/server directory to install the required npm packages:

cd Rocket.Chat./programs/server
npm install

Before we can to a test run, we need to define temporarily some constants that the Rocket.Chat server requires to run:

export ROOT_URL=http://chat.example.com:3000
export MONGO_URL=mongodb://localhost:27017/rocketchat
export MONGO_OPLOG_URL=mongodb://localhost:27017/local?replSet=rs01
export PORT=3000

Make sure to replace chat.example.com with your own domain!
Now, change back to the Rocket.Chat directory and try to give the server a first kickstart:

cd ../../
node main.js

Hopefully, something like this should show up (after a little while):

➔ +---------------------------------------------+
➔ |                SERVER RUNNING               |
➔ +---------------------------------------------+
➔ |                                             |
➔ |  Rocket.Chat Version: 3.0.3                 |
➔ |       NodeJS Version: 12.14.0 - x64         |
➔ |             Platform: linux                 |
➔ |         Process Port: 3000                  |
➔ |             Site URL: http://0.0.0.0:3000/  |
➔ |     ReplicaSet OpLog: Disabled              |
➔ |          Commit Hash: e73dc78ffd            |
➔ |        Commit Branch: HEAD                  |
➔ |                                             |
➔ +---------------------------------------------+

If it does, stop the Rocket.Chat server with Ctrl + C and leave the rocket user account with exit.

Finally, we need to set up a Systemd unit service for Rocket.Chat, so that we can handle it as any other service and also enable it to run at startup. For that, create the fiel rocketchat.server under /etc/systemd/system/:

sudo vi /etc/system/rocketchat.service

Copy and paste the following content into this new file:

[Unit]
Description=Rocket.Chat server
After=network.target nss-lookup.target mongod.target

[Service]
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=rocketchat
User=rocket
Environment=MONGO_URL=mongodb://localhost:27017/rocketchat ROOT_URL=https://chat.example.com PORT=3000
ExecStart=/usr/local/bin/node /opt/rocket/Rocket.Chat/main.js

[Install]
WantedBy=multi-user.target

Make systemd check for new services and start the new Rocket.Chat server:

sudo systemctl daemon-reload
sudo systemctl start rocketchat.service

Give the server a couple of seconds to start and then check out if it is running:

sudo systemctl status rocketchat.service

If things turn our right, the status message should look more or less like that:

* rocketchat.service - Rocket.Chat server
   Loaded: loaded (/etc/systemd/system/rocketchat.service; disabled; vendor preset: enabled)
   Active: active (running) since Sun 2020-03-12 15:18:28 UTC; 1min ago
 Main PID: 12693 (node)
    Tasks: 10 (limit: 2319)
   CGroup: /system.slice/rocketchat.service
           `-12693 /usr/local/bin/node /opt/rocket/Rocket.Chat/main.js

Now, we are going to enable the Rocket.Chat service at startup:

systemctl enable rocketchat.service

We are already able to use Rocket.Chat in the browser and probably with the Windows or iOS desktop app. But for some mobile apps, we will need to do a final tweak in the Nginx configuration. It's called setting up a reverse proxy. Remember that we already configured a file for our domain and saved it into /etc/nginx/sites-available/chat.example.com.conf? We are going to complete this configuration file with a couple of lines. Open it again with

sudo vi /etc/nginx/sites-available/chat.example.com.conf

And now match its content with the following lines:

upstream rocketchat_backend {
  server 127.0.0.1:3000;
}

server {
    listen 80;
    server_name chat.example.com;

    include snippets/letsencrypt.conf;
    return 301 https://chat.example.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name chat.example.com;

    ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/chat.example.com/chain.pem;
    include snippets/ssl.conf;

    access_log /var/log/nginx/chat.example.com-access.log;
    error_log /var/log/nginx/chat.example.com-error.log;

    location / {
        proxy_pass http://rocketchat_backend/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forward-Proto http;
        proxy_set_header X-Nginx-Proxy true;

        proxy_redirect off;
    }
}

Now, reload the Nginx service one last time for the changes to take effect:

sudo systemctl reload nginx

Fuentes

Créditos