Loading...

Install Mattermost Server on CentOS 8|RHEL 8

In this guide, we’ll explore how to install Mattermost on CentOS 8|RHEL 8 with Nginx as reverse proxy. Mattermost is free and open-source online team collaboration and chat platform with hundreds of existing integrations from Mattermost and the community. This enables you to build out custom workflows that scale to tens of thousands of concurrent users. You can easily integrate securely with most popular DevOps tools (CI/CD, bots, Git). Mattermost can be installed on premise infrastructure, in the Cloud, or with hybrid architectures deployment – both public and private clouds. For AWS, Azure, and Google Cloud pre-built open source images are supported for easy installations. Mattermost can be accessed from the web or your favorite device – iOS, Android, Windows, Linux, and Mac.
Install Mattermost Server on CentOS 8|RHEL 8

Let’s begin to install Mattermost on CentOS 8|RHEL 8 With Nginx reverse proxy and optionally configure secure connection with Let’s Encrypt SSL certificate.

Step 1: Update System

Ensure your system is updated.

$sudo yum -y update

You may need to reboot your system after the upgrade.

$sudo reboot

Step 2: Install Database Server

Our Mattermost server will need a Database server to store its data. For this purpose, we’ll use the MariaDB database server.

$sudo yum -y install @mariadb
$sudo systemctl enable --now mariadb
$sudo mysql_secure_installation

After database installation, login to MariaDB shell and create database and user for Mattermost.

$ mysql -u root -p
CREATE DATABASE mattermost;
GRANT ALL PRIVILEGES ON mattermost.* TO mattermost@localhost IDENTIFIED BY 'Str0ngPass';
FLUSH PRIVILEGES;
QUIT;

Step 3: Install Mattermost Server on CentOS 8|RHEL 8

Add system user to manage Mattermost service.

$sudo useradd -d /opt/mattermost -U -M mattermost

Now install Mattermost Server on CentOS 8|RHEL 8 Linux. The latest release of Mattermost is available on the Mattermost download page. As of this writing, the latest version available is 6.1.0.

$wget https://releases.mattermost.com/6.1.0/mattermost-6.1.0-linux-amd64.tar.gz

Extract the archive after the download is complete.

$tar xvf mattermost-6.1.0-linux-amd64.tar.gz

Move the extracted file to the /opt directory.

$sudo mv mattermost /opt

Create the storage directory for files and images that your users post to Mattermost.

$sudo mkdir /opt/mattermost/data

Set directory permissions.

$sudo chown -R mattermost:mattermost /opt/mattermost
$sudo chmod -R g+w /opt/mattermost

Configure the database driver.

$sudo vim /opt/mattermost/config/config.json

We need to set:

  • Set “DriverName” to “mysql
  • Set ‘DataSource” to:
"mmuser:<mmuser-password>@tcp(<host-name-or-IP>:3306)/mattermost?charset=utf8mb4,utf8&readTimeout=30s&writeTimeout=30s"

So for me, this will be:

"SqlSettings": {
        "DriverName": "mysql",
        "DataSource": "mattermost:Str0ngPass@tcp(localhost:3306)/mattermost?charset=utf8mb4,utf8\u0026readTimeout=30s\u0026writeTimeout=30s",
        "DataSourceReplicas": [],
        "DataSourceSearchReplicas": [],
        "MaxIdleConns": 20,
        "ConnMaxLifetimeMilliseconds": 3600000,
        "MaxOpenConns": 300,
        "Trace": false,
        "AtRestEncryptKey": "myyti1r597i99qrk7eu91ywqhaawz4md",
        "QueryTimeout": 30
    },

Change to the mattermost directory to test the Mattermost server.

$cd /opt/mattermost

Start the Mattermost server as the user mattermost:

$ sudo -u mattermost ./bin/mattermost
{"level":"info","ts":1583869117.6809375,"caller":"utils/i18n.go:83","msg":"Loaded system translations","for locale":"en","from locale":"/opt/mattermost/i18n/en.json"}
{"level":"info","ts":1583869117.6810265,"caller":"app/server_app_adapters.go:58","msg":"Server is initializing..."}
{"level":"info","ts":1583869117.6850379,"caller":"sqlstore/supplier.go:221","msg":"Pinging SQL","database":"master"}
{"level":"info","ts":1583869118.8863454,"caller":"sqlstore/upgrade.go:111","msg":"The database schema version has been set","version":"5.20.0"}
{"level":"error","ts":1583869121.576649,"caller":"app/server_app_adapters.go:129","msg":"SiteURL must be set. Some features will operate incorrectly if the SiteURL is not set. See documentation for details: http://about.mattermost.com/default-site-url"}
{"level":"info","ts":1583869121.5776517,"caller":"app/license.go:39","msg":"License key from https://mattermost.com required to unlock enterprise features."}
{"level":"info","ts":1583869121.5779395,"caller":"app/migrations.go:26","msg":"Migrating roles to database."}
{"level":"info","ts":1583869121.6382146,"caller":"sqlstore/post_store.go:1354","msg":"Post.Message has size restrictions","max_characters":16383,"max_bytes":65535}
{"level":"info","ts":1583869121.6425729,"caller":"app/migrations.go:102","msg":"Migrating emojis config to database."}
{"level":"info","ts":1583869122.121464,"caller":"mlog/log.go:167","msg":"Starting up plugins"}
{"level":"info","ts":1583869122.1215749,"caller":"app/plugin.go:199","msg":"Syncing plugins from the file store"}
{"level":"info","ts":1583869123.3940613,"caller":"mlog/sugar.go:19","msg":"Ensuring Surveybot exists","plugin_id":"com.mattermost.nps"}
{"level":"info","ts":1583869123.4156811,"caller":"mlog/sugar.go:19","msg":"Surveybot created","plugin_id":"com.mattermost.nps"}
{"level":"info","ts":1583869123.432906,"caller":"mlog/sugar.go:19","msg":"Upgrade detected. Checking if a survey should be scheduled.","plugin_id":"com.mattermost.nps"}
{"level":"info","ts":1583869123.5542266,"caller":"mlog/sugar.go:19","msg":"Scheduling next survey for Mar 31, 2020","plugin_id":"com.mattermost.nps"}
{"level":"info","ts":1583869123.8526862,"caller":"app/server.go:232","msg":"Current version is 5.20.0 (5.20.1/Sun Feb 16 15:51:14 UTC 2020/0e1a9f7e530061cdd2c7c17899e458afe2c83a9b/551cbd55b9c0d896b5886f42fc0193c9b97edb33)","current_version":"5.20.0","build_number":"5.20.1","build_date":"Sun Feb 16 15:51:14 UTC 2020","build_hash":"0e1a9f7e530061cdd2c7c17899e458afe2c83a9b","build_hash_enterprise":"551cbd55b9c0d896b5886f42fc0193c9b97edb33"}
{"level":"info","ts":1583869123.8527322,"caller":"app/server.go:241","msg":"Enterprise Build","enterprise_build":true}
{"level":"info","ts":1583869123.8527455,"caller":"app/server.go:247","msg":"Printing current working","directory":"/opt/mattermost"}
{"level":"info","ts":1583869123.852752,"caller":"app/server.go:248","msg":"Loaded config","source":"file:///opt/mattermost/config/config.json"}
{"level":"error","ts":1583869123.8604512,"caller":"mlog/log.go:175","msg":"RPC call OnConfigurationChange to plugin failed.","plugin_id":"com.mattermost.nps","error":"connection is shut down"}
{"level":"error","ts":1583869123.89252,"caller":"mlog/log.go:175","msg":"RPC call OnConfigurationChange to plugin failed.","plugin_id":"com.mattermost.nps","error":"connection is shut down"}
{"level":"info","ts":1583869123.894262,"caller":"jobs/workers.go:68","msg":"Starting workers"}
{"level":"info","ts":1583869123.8990135,"caller":"app/web_hub.go:75","msg":"Starting websocket hubs","number_of_hubs":2}
{"level":"info","ts":1583869123.9066868,"caller":"jobs/schedulers.go:74","msg":"Starting schedulers."}
{"level":"info","ts":1583869123.9202466,"caller":"app/server.go:470","msg":"Starting Server..."}
{"level":"info","ts":1583869123.9206858,"caller":"app/server.go:538","msg":"Server is listening on [::]:8065","address":"[::]:8065"}

Step 4: Configure Mattermost systemd unit file

Create a systemd unit file for Mattermost:

$sudo tee /etc/systemd/system/mattermost.service<<EOF
[Unit]
Description=Mattermost
After=syslog.target network.target mariadb.service

[Service]
Type=notify
WorkingDirectory=/opt/mattermost
User=mattermost
ExecStart=/opt/mattermost/bin/mattermost
PIDFile=/var/run/mattermost.pid
TimeoutStartSec=3600
LimitNOFILE=49152

[Install]
WantedBy=multi-user.target
EOF

Disable SELinux or set it permissive mode

$sudo setenforce 0
$sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/g' /etc/selinux/config

Make the service executable.

$sudo systemctl daemon-reload
$sudo systemctl enable --now mattermost

Confirm service status.

$ systemctl status mattermost.service 
● mattermost.service - Mattermost
   Loaded: loaded (/etc/systemd/system/mattermost.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2020-03-13 20:01:03 EAT; 2min 47s ago
 Main PID: 9154 (mattermost)
    Tasks: 16 (limit: 11497)
   Memory: 114.2M
   CGroup: /system.slice/mattermost.service
           ├─9154 /opt/mattermost/bin/mattermost
           └─9224 plugins/com.mattermost.nps/server/dist/plugin-linux-amd64

Mar 13 20:01:02 cent8.novalocal mattermost[9154]: {"level":"info","ts":1584118862.898295,"caller":"app/server.go:247","msg":"Printing current working",>
Mar 13 20:01:02 cent8.novalocal mattermost[9154]: {"level":"info","ts":1584118862.8983018,"caller":"app/server.go:248","msg":"Loaded config","source":">
Mar 13 20:01:02 cent8.novalocal mattermost[9154]: {"level":"info","ts":1584118862.920317,"caller":"sqlstore/post_store.go:1354","msg":"Post.Message has>
Mar 13 20:01:03 cent8.novalocal mattermost[9154]: {"level":"info","ts":1584118862.9979806,"caller":"jobs/workers.go:68","msg":"Starting workers"}
Mar 13 20:01:03 cent8.novalocal mattermost[9154]: {"level":"info","ts":1584118863.0024703,"caller":"app/web_hub.go:75","msg":"Starting websocket hubs",>
Mar 13 20:01:03 cent8.novalocal mattermost[9154]: {"level":"info","ts":1584118863.0136616,"caller":"jobs/schedulers.go:74","msg":"Starting schedulers."}
Mar 13 20:01:03 cent8.novalocal mattermost[9154]: {"level":"info","ts":1584118863.0337238,"caller":"app/server.go:470","msg":"Starting Server..."}
Mar 13 20:01:03 cent8.novalocal mattermost[9154]: {"level":"info","ts":1584118863.033907,"caller":"app/server.go:538","msg":"Server is listening on [::>
Mar 13 20:01:03 cent8.novalocal mattermost[9154]: {"level":"info","ts":1584118863.0339284,"caller":"commands/server.go:105","msg":"Sending systemd READ>
Mar 13 20:01:03 cent8.novalocal systemd[1]: Started Mattermost.

Verify that Mattermost is running.

$ curl http://localhost:8065

You should see the HTML that’s returned by the Mattermost server.

Step 5: Install and Configure Nginx

When running Mattermost in production setting, use a proxy server for greater security and performance of Mattermost.

Install Nginx on CentOS / RHEL Linux machine.

$sudo dnf -y install nginx

Start and enable Nginx service.

$sudo systemctl enable --now nginx

Then configure Nginx web server as a proxy for Mattermost Server.

$sudo vi /etc/nginx/conf.d/mattermost.conf

Paste and edit below code snippet to the file to configure Nginx mattermost.

upstream backend {
   server 127.0.0.1:8065;
   keepalive 32;
}

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mattermost_cache:10m max_size=3g inactive=120m use_temp_path=off;

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

   location ~ /api/v[0-9]+/(users/)?websocket$ {
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "upgrade";
       client_max_body_size 50M;
       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
       proxy_set_header X-Frame-Options SAMEORIGIN;
       proxy_buffers 256 16k;
       proxy_buffer_size 16k;
       client_body_timeout 60;
       send_timeout 300;
       lingering_timeout 5;
       proxy_connect_timeout 90;
       proxy_send_timeout 300;
       proxy_read_timeout 90s;
       proxy_pass http://backend;
   }

   location / {
       client_max_body_size 50M;
       proxy_set_header Connection "";
       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
       proxy_set_header X-Frame-Options SAMEORIGIN;
       proxy_buffers 256 16k;
       proxy_buffer_size 16k;
       proxy_read_timeout 600s;
       proxy_cache mattermost_cache;
       proxy_cache_revalidate on;
       proxy_cache_min_uses 2;
       proxy_cache_use_stale timeout;
       proxy_cache_lock on;
       proxy_http_version 1.1;
       proxy_pass http://backend;
   }
}

Modify mattermost.example.com to set correct value for your Mattermost domain.

Validate your Nginx configuration file.

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Restart Nginx if all looks good.

sudo systemctl restart nginx

Open http and https ports on Firewalld.

sudo firewall-cmd --add-service={http,https} --permanent
sudo firewall-cmd --reload

Confirm that the status is running.

$ systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2020-03-13 20:17:05 EAT; 2min 9s ago
  Process: 9772 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 9769 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 9768 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
 Main PID: 9774 (nginx)
    Tasks: 3 (limit: 11497)
   Memory: 5.2M
   CGroup: /system.slice/nginx.service
           ├─9774 nginx: master process /usr/sbin/nginx
           ├─9775 nginx: worker process
           └─9776 nginx: cache manager process

Mar 13 20:17:05 cent8.novalocal systemd[1]: Starting The nginx HTTP and reverse proxy server...
Mar 13 20:17:05 cent8.novalocal nginx[9769]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Mar 13 20:17:05 cent8.novalocal nginx[9769]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Mar 13 20:17:05 cent8.novalocal systemd[1]: nginx.service: Failed to parse PID from file /run/nginx.pid: Invalid argument
Mar 13 20:17:05 cent8.novalocal systemd[1]: Started The nginx HTTP and reverse proxy server.

You should be able to access Mattermost domain configured on Nginx.

$ curl mattermost.example.com

Step 6: Configure Mattermost Server

We can now start to configure the Mattermost server by opening the domain configured on Nginx.

http://mattermost.example.com

Create an admin user on the first page – The user will be able to create or invite other new users.

Choose to create a team or proceed straight to the console.

If you chose to create a team, provide team name and click Next.

Set team URL and click Finish.

Step 7: Configure Let’s Encrypt / Custom SSL Certificate

You can use SSL to ensure there is a greater security by ensuring that communications between Mattermost clients and the Mattermost server are encrypted. It also allows you to configure NGINX to use the HTTP/2 protocol.

Obtain Let’s Encrypt SSL certificate for your domain. First download the certbot script.

sudo dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
sudo yum -y install certbot

Stop Nginx Service.

sudo systemctl stop nginx

Then set Domain and Email for the expiry alerts and obtain a free Let’s Encrypt certificate.

export DOMAIN="mattermost.example.com"
export EMAIL_ALERTS="admin@example.com"
sudo certbot certonly --standalone -d $DOMAIN --preferred-challenges http --agree-tos -n -m $EMAIL_ALERTS --keep-until-expiring

Update your nginx configuration file to set SSL.

.
.
.
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mattermost_cache:10m max_size=3g inactive=120m use_temp_path=off;

server {
   listen 80 default_server;
   server_name   mattermost.example.com ;
   return 301 https://$server_name$request_uri;
}

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

  ssl on;
  ssl_certificate /etc/letsencrypt/live/{domain-name}/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/{domain-name}/privkey.pem;
  ssl_session_timeout 1d;
  ssl_protocols TLSv1.2;
  ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:50m;
  # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
  add_header Strict-Transport-Security max-age=15768000;
  # OCSP Stapling ---
  # fetch OCSP records from URL in ssl_certificate and cache them
  ssl_stapling on;
  ssl_stapling_verify on;


  location ~ /api/v[0-9]+/(users/)?websocket$ {
    proxy_set_header Upgrade $http_upgrade;
    .
    .
    .

location / {
    proxy_http_version 1.1;
    .
    .
    .

Restart Nginx.

sudo systemctl restart nginx

Confirm the service is now on https from your web browser.