Running Your Own Chat Server with Mattermost

- linux self-host

Introduction

Mattermost is an open core team chat application similar to popular services such as Slack and Discord. Unlike those two, Mattermost is self-hosted, rather than SaaS, which gives you better control over your team’s chat data, making it the better choice for the privacy conscious and organization with stricter security needs.

In this guide, we’ll go over setting up your own Mattermost server in the cloud.

Prerequisites

General familiarity with the command line and SSH is recommended for this guide. You’ll also need a Linux server to work with - preferably, one in the cloud with something like DigitalOcean, Linode, GCP, etc. For production use, please check the hardware requirements to determine how much resource to allocate for your host.

For this guide, we cover CentOS(RHEL) 8, Debian 10, and Ubuntu 18.04 with Mattermost 5.16.3. If you are on a different distribution or using a different version of Mattermost, please double check the software requirements in the Mattermost documentation.

Setup the Database

We’re going to start by installing and setting up the database for our Mattermost server. Mattermost works with either MySQL or PostgreSQL. For this guide, we will be using Postgres, as it is often considered to be the more robust choice.

Install the PostgreSQL packages using the distribution’s package manager:

On Ubuntu/Debian:

sudo apt install postgresql postgresql-contrib

On CentOS/RHEL:

sudo dnf install postgresql-server postgresql-contrib

On CentOS/RHEL, you’ll have to create a database cluster with the following command:

postgresql-setup --initdb --unit postgresql

Next, we’ll have to edit the authentication settings to allow Mattermost to connect to the PostgreSQL database. To do this, open the pg_hba.conf file, located at /etc/postgresql/10/main/pg_hba.conf on Ubuntu/Debian and /var/lib/pgsql/data/pg_ba.conf on CentOS/RHEL. Near the end of the file, you should see the following lines:

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            ident
# IPv6 local connections:
host    all             all             ::1/128                 ident

There are three lines of configurations, here; the lines beginning with # are just comments. On the first line, replace peer with trust. Then, on the next two, replace ident with md5. On Ubuntu, it may already have some of these set. Just ensure it matches the below changes:

# 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            md5
# IPv6 local connections:
host    all             all             ::1/128                 md5

Once saved, start the PostgreSQL server and enable it to start on boot:

sudo systemctl start postgresql
sudo systemctl enable postgresql

To begin setting up the database, we’ll have to switch to the postgres user, which should have been created during the installation process.

Change users:

sudo -iu postgres

Then, start the PostgreSQL interactive terminal:

psql

You should see a new prompt that shows postgres=#. From this interactive terminal, we’re going to create the database as well as a user that our Mattermost server will use. In the following commands, replace the appropriate variables with the names/passwords of your choice.

Create the database:

postgres=# CREATE DATABASE your_db_name;

Create a user and password:

postgres=# CREATE USER your_db_user WITH PASSWORD 'your_password';

Grant the newly create user access to the database:

postgres=# GRANT ALL PRIVILEGES ON DATABASE your_db_name TO your_db_user;

With that finished, we can now exit the PostgreSQL interactive terminal:

postgres=# \q

Exit the postgres user as well:

exit # alternatively, you can use CTRL + d

Reload PostgreSQL to apply the changes we’ve made:

sudo systemctl reload postgresql

Finally, let’s test to ensure that our user can access the database. Enter your password when prompted:

psql -d your_db_name -U your_db_user -W

If you get errors, review the database steps again carefully. In particular, ensure that the pg_hba.conf configurations are set correctly. Once you do get connected successfully, exit the interactive terminal and move on to the next step.

Install the Mattermost Server

Mattermost is not available in the default repositories of the distribution package managers and requires manual installation. Go to the Mattermost download page to get the URL of the latest release. This guide will install 5.16.3, so the download URL is https://releases.mattermost.com/5.16.3/mattermost-5.16.3-linux-amd64.tar.gz.

On the server, use curl to download the tar file:

curl -O https://releases.mattermost.com/5.16.3/mattermost-5.16.3-linux-amd64.tar.gz

We’re going to extract the contents to /opt - which is a standard directory for manually installed third-party applications. If the tar command is not found, install it with the package manager.

sudo tar -C /opt -xzf mattermost-5.16.3-linux-amd64.tar.gz

Create a data directory for storage (this is where all the files/images posted within Mattermost will be stored):

sudo mkdir -p /opt/mattermost/data

For the sake of security, we do not want Mattermost to be run as the root user, so we’ll create a user and group for this purpose:

sudo useradd -rU mattermost

Give access to the Mattermost directory to the new user/group:

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

Next, we’re going to edit the Mattermost configuration file to give it access to the database we created. Open the /opt/mattermost/config/config.json file and look for the "DriverName" and "DataSource" options under "SqlSettings". We’re going to make the following edits:

"SqlSettings": {
  "DriverName": "postgres",
  "DataSource": "postgres://your_db_user:your_password@localhost:5432/your_db_name?sslmode=disable&connect_timeout=10",
...

It is a JSON file, so be mindful of the formatting, making sure the quotation marks and commas are in the right places.

At this point, we can test the Mattermost server to ensure it runs properly. Execute the mattermost binary as the mattermost user:

sudo -u mattermost /opt/mattermost/bin/mattermost

You should get some log outputs. Look for a line that shows something like:

{"level":"info","ts":1573359168.5523689,"caller":"app/server.go:489","msg":"Server is listening on [::]:8065"}

From your browser, enter the IP address of the server followed by the port number you see at the end of the above output - for example: 127.0.0.1:8065. If everything worked correctly, you should see a page prompting you to create a new account. This account will be the default admin user of the Mattermost instance. If you want, you can do so at this time. Once you’re done, go back to the command line and enter ctrl + c to quit the Mattermost server.

We have one last thing to do to finalize the installation of Mattermost. We’re going to have systemd manage the Mattermost process as a service. This makes it easier to start, restart, stop, and enable the server. Using a text editor of your choice, reate and open the file: /etc/systemd/system/mattermost.service, then add the following configurations:

[Unit]
Description=Mattermost
After=syslog.target network.target postgresql-9.4.service

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

[Install]
WantedBy=multi-user.target

Reload the systemd services to apply the new changes:

sudo systemctl daemon-reload

Start and enable the new mattermost service just as we did with postgresql:

sudo systemctl start mattermost
sudo systemctl enable mattermost

If you go back to the browser and enter the IP and port again, you should see that Mattermost is running as it was before. At this point, you actually have a fully functional Mattermost chat server. You can begin setting up teams and users and get to chatting. Before doing so, however, we’ll go over configuring the web server to make it easier and more secure to access your new Mattermost instance.

Configuring the Web Server

In this section, we’re going to set up a web server to allow you to access the Mattermost server on the standard web ports of 80 and 443. This means you’ll no longer need to add a port at the end of your URL. This is a minor thing if you’re mostly using the mobile or desktop clients, but it can be a major improvement if you use the web client. We’ll also set up an SSL to encrypt communication between your clients and the server.

Mattermost has a built in web server (it’s how we are able to access it via the browser), but we’re going to use Nginx as a proxy. While Mattermost itself is adequate for most use cases, it is trivial enough to set up Nginx, which will provide better performance, security, and stability.

We’ll also be setting up an SSL with Let’s Encrypt. This requires a fully qualified domain. If you have one, point the DNS A records for the domain/subdomain to the IP address of the server. If you don’t have one, you can use something like nip.io.

Set up Nginx

To start, install Nginx:

Ubuntu/Debian:

sudo apt install nginx

CentOS/RHEL:

sudo dnf install nginx

Start and enable Nginx:

sudo systemctl start nginx
sudo systemctl enable nginx

Quickly test to ensure Nginx is running. You should see a 200 OK status:

curl -SI http://localhost

Next, we’re going to add the Mattermost Nginx configurations. Create a file at /etc/nginx/sites-available/mattermost.conf (feel free to change the conf file name if you want). On CentOS, you’ll need to create the sites-available directory:

sudo mkdir /etc/nginx/sites-available

Put the below configurations into that file, making the appropriate edits for your server’s IP and your domain name:

upstream backend {
   server your_server_ip: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    your_domain_name;

   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;
   }
}

Once created, link the configuration from sites-available to the active conf directories:

Ubuntu/Debian:

sudo ln -s /etc/nginx/sites-available/mattermost.conf /etc/nginx/sites-enabled/mattermost.conf

CentOS/RHEL:

sudo ln -s /etc/nginx/sites-available/mattermost.conf /etc/nginx/conf.d/mattermost.conf

On CentOS/RHEL, you may need to make changes to the SELinux configurations for the proxy to work properly:

setsebool -P httpd_can_network_connect 1

Restart the Nginx daemon:

sudo systemctl restart nginx

Now, if you go to your domain (or the nip.io domain) on the browser, you should see Mattermost. Let’s move on to set up the Let’s Encrypt SSL to secure our server.

Setup a Let’s Encrypt SSL

To begin, install Certbot:

Ubuntu/Debian:

sudo apt install certbot python-certbot-nginx

For CentOS/RHEL, we’ll have to install it manually:

curl -O https://dl.eff.org/certbot-auto
sudo mv certbot-auto /usr/local/bin/certbot-auto
sudo chown root /usr/local/bin/certbot-auto
sudo chmod 0755 /usr/local/bin/certbot-auto

Run Certbot to generate the SSL. You’ll be asked a few questions during the process - enter them as appropriate. One of the questions will ask if you would like to set up a redirect. Select the option for “Yes”:

Ubuntu/Debian:

sudo certbot --nginx -d your_domain_name

CentOS/RHEL:

sudo /usr/local/bin/certbot-auto --nginx -d your_domain_name

Once Certbot finishes running, go on the browser and enter the domain for your Mattermost instance. It should now automatically redirect to https and have a secure connection established. That’s it - you should now have a running Nginx web server using Let’s Encrypt for SSL serving as the proxy for your Mattermost server.

Conclusion

You now have a running chat server with Mattermost for your team. It’s a feature packed chat application; to make the most of it, you should look over the official Mattermost documentation for tips on using and administering Mattermost. Have fun and chat away!