How to install Mattermost on Ubuntu with PostgreSQL and HTTPS
Install Mattermost from its official apt repository on Ubuntu 24.04 with a local PostgreSQL database, HTTPS through Caddy, a tight firewall and backups.
- Intermediate
- 40 min read
- Updated
Tested on: Ubuntu 24.04 LTS
This guide is not available in your language yet, so it is shown in English.
On this page
- Prerequisites
- Step 1 — Install PostgreSQL and create the database
- Step 2 — Add Mattermost's apt repository and install the package
- Step 3 — Configure the database connection and Site URL
- Step 4 — Start Mattermost
- Step 5 — Publish Mattermost over HTTPS with Caddy
- Step 6 — Close every port except SSH and the web
- Step 7 — Create the first administrator and lock down sign-up
- Back up and restore
- Update Mattermost
- Troubleshooting
- The service stops right after you edit config.json
- pq: password authentication failed for user "mmuser"
- permission denied for schema public
- The page loads but messages only appear after a refresh
- Calls connect but nobody can hear each other
- Next steps
Mattermost is a self-hosted team messaging platform with channels, threads, direct messages, file sharing and built-in voice calls. Running it on your own server keeps conversations and files on infrastructure you control. This guide installs Mattermost from Mattermost's signed apt repository on Ubuntu 24.04 LTS, connects it to a local PostgreSQL database, publishes it over HTTPS through Caddy, closes every port except SSH and web traffic, and shows how to create the first administrator, back up, restore and upgrade the server.
Prerequisites
- A server running Ubuntu 24.04 LTS on x86_64 (amd64). Mattermost's install guide lists Ubuntu 20.04, 22.04 and 24.04 LTS. Its repository already publishes packages for Ubuntu 26.04, but the guide does not list that release yet, and the repository setup script accepts Ubuntu releases only.
- A non-root user with
sudorights and SSH key login: see Secure a new Linux server and Set up SSH keys. - A domain name such as
chat.example.comwith an A record (and AAAA record if you use IPv6) pointing to the server. - Caddy installed on the server as described in Caddy reverse proxy.
- An SMTP account for email notifications and invitations. Mattermost runs without it, but users then get no email.
Sizing from Mattermost's requirements page:
| Resource | Minimum (official) | Suggested starting point |
|---|---|---|
| CPU | 1 vCPU for up to about 1,000 users | 2 vCPU, so PostgreSQL and Mattermost do not compete |
| RAM | 2 GB for up to about 1,000 users | 4 GB with PostgreSQL on the same server |
| Disk | Not published for small deployments | 20 GB plus the file uploads you expect |
| Database | PostgreSQL 14 or later (15 or later from Mattermost v12.0) | Ubuntu's own PostgreSQL package |
Step 1 — Install PostgreSQL and create the database
Install PostgreSQL from Ubuntu's archive. Ubuntu 24.04 ships PostgreSQL 16, which meets Mattermost's requirement, and the server only listens on localhost by default:
sudo apt update
sudo apt install postgresql
openssl rand -hex 24The last command prints a random password for the database user; copy it. Then open the PostgreSQL shell:
sudo -u postgres psqlRun these statements from Mattermost's database guide, replacing change-me with the password you generated. The last three lines are required on PostgreSQL 15 and later, where ordinary users can no longer create tables in the public schema:
CREATE DATABASE mattermost WITH ENCODING 'UTF8' LC_COLLATE='en_US.UTF-8' LC_CTYPE='en_US.UTF-8' TEMPLATE=template0;
CREATE USER mmuser WITH PASSWORD 'change-me';
GRANT ALL PRIVILEGES ON DATABASE mattermost TO mmuser;
ALTER DATABASE mattermost OWNER TO mmuser;
\c mattermost
ALTER SCHEMA public OWNER TO mmuser;
GRANT USAGE, CREATE ON SCHEMA public TO mmuser;
\qCheck that the new user can log in over TCP; psql asks for the password and then prints the connection details:
psql -h localhost -U mmuser -d mattermost -c '\conninfo'Step 2 — Add Mattermost's apt repository and install the package
Mattermost provides a repository setup script. It checks that you run a supported Ubuntu release, downloads Mattermost's signing key, verifies its fingerprint, writes /etc/apt/sources.list.d/mattermost.list and runs apt update. Download it and read it before you run it:
curl -fsSL https://deb.packages.mattermost.com/repo-setup.sh -o mattermost-repo-setup.sh
less mattermost-repo-setup.sh
sudo bash mattermost-repo-setup.sh mattermost
sudo apt install mattermostThe mattermost argument adds only the Mattermost repository. Without it, the script also adds the Nginx, PostgreSQL and Certbot repositories, which this guide does not need. The official one-line equivalent is curl -o- https://deb.packages.mattermost.com/repo-setup.sh | sudo bash -s mattermost.
The package installs into /opt/mattermost and creates a mattermost system user. The service is not enabled or started yet. Check the installed version:
apt-cache policy mattermostStep 3 — Configure the database connection and Site URL
Create the configuration file from the shipped defaults, readable only by the mattermost user, and open it in an editor:
sudo install -C -m 600 -o mattermost -g mattermost /opt/mattermost/config/config.defaults.json /opt/mattermost/config/config.json
sudo nano /opt/mattermost/config/config.jsonFind the following keys inside their existing sections and change only their values. The snippet shows the keys, not the whole file:
{
"ServiceSettings": {
"SiteURL": "https://chat.example.com"
},
"SqlSettings": {
"DriverName": "postgres",
"DataSource": "postgres://mmuser:change-me@localhost:5432/mattermost?sslmode=disable&connect_timeout=10"
},
"SupportSettings": {
"SupportEmail": "[email protected]"
}
}SiteURLmust be the exact public address users open, includinghttps://. Links in emails, notifications and the WebSocket connection depend on it.DataSourcecontains the database password from Step 1. A hex password needs no URL encoding.sslmode=disableis fine because PostgreSQL runs on the same server and the connection never leaves localhost.
Mattermost's guide recommends tying the service to PostgreSQL when both run on the same host. Add this through a systemd drop-in, which survives package upgrades, instead of editing the packaged unit file:
sudo systemctl edit mattermostPaste these lines into the editor between the comment markers, then save:
[Unit]
After=postgresql.service
BindsTo=postgresql.serviceStep 4 — Start Mattermost
sudo systemctl start mattermost
sudo systemctl status mattermost --no-pager
curl -s http://localhost:8065 | head -n 5
sudo systemctl enable mattermost.serviceThe first start creates the database schema and can take a minute. The curl command should print the beginning of the Mattermost HTML page. If the service stops instead, read the log with sudo journalctl -u mattermost -n 50 --no-pager; see Troubleshooting below.
Step 5 — Publish Mattermost over HTTPS with Caddy
Add a site block for your domain to /etc/caddy/Caddyfile:
chat.example.com {
reverse_proxy 127.0.0.1:8065
}Reload Caddy and check the response:
sudo systemctl reload caddy
curl -I https://chat.example.comYou should see HTTP/2 200 and a valid certificate. Caddy obtains the certificate from Let's Encrypt, proxies WebSocket upgrades automatically and sets the X-Forwarded-For and X-Forwarded-Proto headers, so no extra options are needed.
If you prefer Nginx, follow Nginx with Certbot and use the server block from Mattermost's NGINX proxy documentation. It has a separate location for the WebSocket path with the Upgrade and Connection headers, a client_max_body_size for uploads and longer proxy timeouts; without those parts, Mattermost connects but stops updating in real time.
Step 6 — Close every port except SSH and the web
Mattermost runs as a normal system service, not in Docker, so ufw does protect port 8065:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verboseFrom another machine, nc -vz your-server-ip 8065 should now be refused or time out, while https://chat.example.com keeps working.
The Calls plugin (voice calls and screen sharing) is enabled by default. Its media server listens on port 8443 over UDP, with TCP 8443 as a fallback for clients that cannot use UDP. If you plan to use Calls, open both:
sudo ufw allow 8443/udp
sudo ufw allow 8443/tcpStep 7 — Create the first administrator and lock down sign-up
Open https://chat.example.com in a browser and create an account. On a new server the first account becomes the system administrator. Mattermost then asks you to create your first team.
Before you invite anyone, open System Console from the product menu and check these settings:
- Authentication > Signup: keep Enable Open Server set to false, which is the default. Users then need an invitation link to create an account.
- Authentication > MFA: allow multi-factor authentication and turn it on for every administrator account.
Then open Environment > SMTP. Invitations, password resets and email notifications depend on it. Enter your relay's server (for example smtp.example.com), port 587, STARTTLS as the connection security, and the SMTP user and password, then click Test Connection.
Back up and restore
Mattermost's state lives in three places: the PostgreSQL database, the configuration in /opt/mattermost/config, and uploaded files in /opt/mattermost/data (when you use local storage, the default). Mattermost's backup guide says to stop the server for the duration of a backup so that the database and the files match.
sudo mkdir -p /opt/backups
sudo chown $USER:$USER /opt/backups
chmod 700 /opt/backups
sudo systemctl stop mattermost
sudo -u postgres pg_dump -Fc mattermost > /opt/backups/mattermost-db-$(date +%F).dump
sudo tar czf /opt/backups/mattermost-files-$(date +%F).tar.gz -C /opt/mattermost config data
sudo systemctl start mattermost
ls -lh /opt/backupsTo restore on a new server, complete Steps 1 to 3 with the same Mattermost version (sudo apt install mattermost=VERSION, where apt-cache madison mattermost lists the versions) and the same database password, but do not start the service. Then load the dump into the empty database and put the files back:
sudo systemctl stop mattermost
sudo -u postgres pg_restore -d mattermost < /opt/backups/mattermost-db-2026-10-09.dump
sudo tar xzf /opt/backups/mattermost-files-2026-10-09.tar.gz -C /opt/mattermost
sudo chown -R mattermost:mattermost /opt/mattermost/config /opt/mattermost/data
sudo systemctl start mattermostReplace the dates with those of your backup files. Copy backups off the server as well, for example with rsync to another machine or to object storage.
Update Mattermost
Read Mattermost's important upgrade notes for every version between yours and the target, and take a backup first. Mattermost's documentation warns that apt upgrade replaces the binary while it is running, so stop the service before you upgrade:
sudo systemctl stop mattermost
sudo apt update && sudo apt upgrade
sudo systemctl start mattermostTwo habits make upgrades predictable:
- Mattermost guarantees backward compatibility only with the last Extended Support Release (ESR). If you have fallen behind, upgrade to the closest ESR first and then to the next one.
apt-cache madison mattermostlists the available versions, andsudo apt install mattermost=11.7.12-0installs a specific one (replace the version with the ESR you need). - To stop routine
apt upgraderuns from upgrading Mattermost unplanned, hold the package withsudo apt-mark hold mattermostand release it withsudo apt-mark unhold mattermostwhen you are ready.
Troubleshooting
The service stops right after you edit config.json
A missing comma or quote makes the file invalid JSON. Check it with sudo python3 -m json.tool /opt/mattermost/config/config.json > /dev/null; the command prints the line of the first error. Also read sudo journalctl -u mattermost -n 50 --no-pager and /opt/mattermost/logs/mattermost.log.
pq: password authentication failed for user "mmuser"
The password in DataSource does not match the database user. Set a new one with sudo -u postgres psql -c "ALTER USER mmuser WITH PASSWORD 'new-hex-password';", update DataSource and restart the service.
permission denied for schema public
On PostgreSQL 15 and later the database owner and schema grants from Step 1 are required. Run the ALTER DATABASE, ALTER SCHEMA and GRANT USAGE, CREATE statements again as the postgres user and restart Mattermost.
The page loads but messages only appear after a refresh
The WebSocket connection fails. Make sure SiteURL matches the address in the browser exactly, including https://. A 403 response on the WebSocket URL in the browser's developer tools usually means a SiteURL mismatch. With Nginx, check that the WebSocket location block from Mattermost's configuration is present.
Calls connect but nobody can hear each other
The call signalling works over HTTPS, but media needs port 8443. Open 8443/udp (and 8443/tcp) in ufw and in any provider or network firewall in front of the server.
Next steps
- Add video meetings next to your chat with Jitsi Meet.
- Compare other self-hosted chat servers: Rocket.Chat and Matrix Synapse with Element.
- Learn more about the proxy in front of Mattermost in Caddy reverse proxy.
- Read the official Mattermost deployment guide for SSO, file storage on S3 and high availability.
- Compare servers for team chat on the team chat hosting page.
Frequently asked questions
Where does Mattermost write its logs?
The service writes to the systemd journal, which you read with sudo journalctl -u mattermost -n 50 --no-pager, and Mattermost keeps its own log file at /opt/mattermost/logs/mattermost.log. Check both first when the service stops or a setting does not take effect.
Why not use Mattermost's Docker setup?
Mattermost's container guide says its Docker deployment should not be used in production because it does not support clustering or high availability out of the box, and presents it for testing and development. For Ubuntu servers the documentation recommends the signed apt repository, which also delivers security updates through apt.
Does the reverse proxy need WebSocket support?
Yes. New messages, typing indicators and presence updates arrive over a WebSocket on the api/v4/websocket path. Caddy proxies WebSocket upgrades without extra settings; with Nginx, use Mattermost's official configuration, which sets the Upgrade and Connection headers.
Which ports must be open to the internet?
SSH, 80 and 443. Mattermost itself listens on port 8065, which stays closed and is reached only through the reverse proxy. If you use the built-in Calls feature, also open 8443/udp and 8443/tcp for call media.
Which HyperDC servers can run Mattermost?
Any HyperDC Linux VPS, VDS or dedicated server with root access and Ubuntu 24.04 LTS. Mattermost publishes 1 vCPU and 2 GB RAM for up to about 1,000 users; give PostgreSQL and file uploads some headroom on top of that.
Sources
- docs.mattermost.com/deployment-guide/server/deploy-linux.html
- docs.mattermost.com/deployment-guide/server/linux/deploy-ubuntu.html
- docs.mattermost.com/deployment-guide/server/prepare-database.html
- docs.mattermost.com/deployment-guide/server/deploy-containers.html
- docs.mattermost.com/deployment-guide/software-hardware-requirements…
- docs.mattermost.com/product-overview/editions-and-offerings.html
- docs.mattermost.com/deployment-guide/server/setup-nginx-proxy.html
- docs.mattermost.com/administration-guide/configure/authentication-c…
- docs.mattermost.com/administration-guide/configure/plugins-configur…
- docs.mattermost.com/deployment-guide/backup-disaster-recovery.html
- docs.mattermost.com/administration-guide/upgrade/upgrading-mattermo…
- docs.mattermost.com/administration-guide/upgrade/prepare-to-upgrade…