Setup a chatmail server for Delta Chat

Setup a chatmail server for Delta Chat

The other night, as in a night many weeks ago, I was listening to a 2.5 Admins episode and they covered a story on the FBI warning the public not to use SMS due to concerns about China intercepting the communications. Thus, they're recommending everyone switch to an end-to-end encrypted messaging platform. I already have one such platform setup, Snikket, and I've been reasonably satisfied with it, but the episode got me wondering what else is out there. Don't ask me what search term I used or what website I ended up on, but I ended up stumbling across Delta Chat and thought it looked interesting. I'm pretty sure I cam across it some time ago and forgot about it, but this time it piqued my interest.

What is Delta Chat?

Delta Chat is an open source instant messaging application that uses email to send and receive messages. You can use traditional email servers (e.g. your existing gmail address) or step up to one of their purpose-built chatmail servers. Delta Chat uses Autocrypt for end-to-end encryption of messages; encryption is enforced for chatmail servers and available when using a traditional email server (I'm not sure of the exact details on establishing encryption with traditional email servers because I jumped straight to chatmail, but their FAQ probably has some useful info).

I was a bit dubious about using email for instant messaging, but a couple weeks of sending messages to myself across iOS, Android, Windows, and Linux proved to be fast and reliable. The user experience is also better in some respects than Snikket. This is not a dig against Snikket, I think it's a great project and I'm not shutting down my instance anytime soon, but it does have some minor annoyances that make the already difficult task of migrating friends and family to your platform that much harder. I'll add a review of Snikket in detail at some point, but for today, just know that it's a worthy contender edged out by Delta Chat in the overall user experience.

While this post is about setting up your own chatmail server, I should note that you don't have to run your own server if that's not your interest. You can use any of instances listed at https://delta.chat/chatmail as your full-time server, or just to check out the platform (that's what I did for a few weeks).

Setup your chatmail server

I don't have a personal email server. I've thought about running one a few times, if for no other reason than to have an assortment of mailboxes to which I can direct the vast quantities of junk companies want to send me, but I've not been motivated enough to act on these thoughts. For this reason, the chatmail server appealed to me: an automated deploy of the necessary pieces to run Delta Chat, with the added benefits of tweaks to improve the chat experience. Below are the steps I took to get this service up and running; you can expect to spend an hour, or so, depending on what things you already have in place.

Get a server

You need a server to host your chatmail service. There are a couple things to keep in mind when considering your options:

  1. This is a communication platform that you, presumably, want to be reliable, so you should put it somewhere that will be reliable.
  2. This is an email server and as such, will need access to the typical email ports.

On the first point: when I first setup my Snikket instance, I ran it locally (i.e. in my basement), routing the traffic through a Linode VPS so as not to expose my public IP (I'll detail this setup at some point). During the testing phase this was fine, but I realized adding my home internet connection to the list of dependencies was an unnecessary potential failure point for something that I wanted to serve as a reliable communication platform. Point being, despite my desire to self-host (on my own hardware) as much as possible, I think Delta Chat is a service better run from a VPS, or other location with high uptime guarantees.

Since I'm assuming you'll use a VPS, the next question is: "who will let you run an email server?" Specifically, if you search the web for information on hosting your own email, you'll find numerous posts stating that port 25 may be blocked by default on your preferred cloud host. For many, a support ticket requesting port 25 be unblocked seems to have been all that is required, but YMMV. The bottom line: do your research before choosing a host.

Personally, I have accounts with Digital Ocean and Linode and have been happy with the service of both (of note, however, is that I've had two VMs have to be relocated to a different physical machine at Linode, due to hardware failures, and have had no such experiences at DO). Most recently, my personal workloads have been running at Linode, so I elected to use them for this service, thinking that more recent activity would make getting port 25 opened up a simpler task. As it turns out, when I spun up a new nanode in the Chicago data center, port 25 was open by default. I don't know if this is common, but it made my job easier.

As for the actual machine:

  • Linode nanode (1 vCPU, 1 GB RAM, 25 GB SSD)
  • Ubuntu 24.04 (you must use a Debian-based distro as the deployment script uses apt)

Prepare your server

There isn't a lot that we need to do to get our server ready, just the basics that you should tackle with any server. If you can SSH into your server, do that here, otherwise you can use the cloud terminal, or whatever they call it.

ℹ️ root user

All the commands in this post are run as root. If you're running as another use, add sudo where appropriate.

First, update the system:

apt update && apt full-upgrade -y && reboot

Next, add your SSH public key (it must be an ed25519 key) to the root user, if you didn't do so during the VPS setup process. Normally, I'd use a different user but, as of this writing, the PyInfra deployment used for chatmail requires you to execute it as root on the remote server.

mkdir ~/.ssh
touch ~/.ssh/authorized_keys

Copy your public key(s) to authorized_keys and verify that you can connect.

We'll also limit SSH access by adding the following file:

mkdir -p /etc/ssh/sshd_config.d

Add our SSH overrides file: touch /etc/ssh/sshd_config.d/delta_chat.conf and open it (nano /etc/ssh/sshd_config.d/delta_chat.conf`) and add the following:

Port 22
PermitRootLogin prohibit-password
PasswordAuthentication no

Make sure that /etc/ssh/sshd_config includes the line Include /etc/ssh/sshd_config.d/*.conf so that our changes will be used to override the defaults, then restart the ssh service.

systemctl restart ssh

We'll enable some additional security measures once chatmail has been setup, but that's it for now.

Get a domain

The second requirement for a chatmail server is to have a domain. This can be whatever you want (assuming nobody's squatting on it), registered with your preferred registrar. Historically, I've used Namecheap, but they've significantly increased their prices lately and there are other less expensive and equally well regarded registrars out there.

For the remainder of this post, we'll assume that the domain we're using is delta.chat.me and its public IP address is 199.52.201.123 (if this is your IP address, I apologize for exposing it to the world, I just made it up).

To get started we need only an A record pointing to our server's public IP, something like:

Type Name IPv4 address TTL
A delta 199.52.201.123 Auto

If you use Cloudflare to manage your DNS, as I am, you'll want to turn off proxying for this record.

Deploy chatmail

We are now ready to begin our chatmail deployment. We'll setup the chatmail repo on your local machine, update a few config parameters, then run the deployment.

I'm running this on a Linux desktop, but you can do the same on Mac or within WSL on Windows. You need to have git and python3 installed on your system.

Clone the repo

We'll first clone the repo and have one of the scripts generate a default configuration:

git clone https://github.com/deltachat/chatmail
cd chatmail
./scripts/initenv.sh

initenv.sh will create chatmail/chatmail.ini with some basic settings for your instance. The defaults are all fine, but feel free to change them to whatever values you see fit. Some of the changes I made include:

mail_domain = delta.chat.me
max_mailbox_size = 250M
delete_mails_after = 30
delete_inactive_users_after = 180
username_min_length = 8
username_max_length = 16
password_min_length = 16

I didn't set any of the privacy_... options because I didn't want to. Just be aware that these will, by default, show up on the website that is generated.

You may also want to make changes to the website that is generated. You can do this via the files in chatmail/www/src. No changes are necessary, but are possible (for example, I added a FAQ page to explain how to join, create a chat, etc.).

Run the deployment

Your first deployment will be a bit more work than subsequent runs because you will need to add several additional DNS records; you will be told what each of the missing records are by one of the deployment scripts.

First things first: if you have a password on your ssh key, you need to add it to the ssh-agent because you won't have an opportunity to enter it when running the script. If your key doesn't have a password, you can skip this step.

eval `ssh-agent -s`
ssh-add ~/.ssh/id_ed25519

Replace ~/.ssh/id_ed25519 with the SSH key you'll be using. Enter your password when prompted, then verify you can ssh into the remote server without a password prompt: ssh delta.chat.me.

We're now ready to run the deployment with a single line:

./scripts/cmdeploy run

You'll see a bunch of actions listed on your terminal. I didn't encounter any errors, so I'll assume you were similarly successful and won't attempt to guess at what issues might arise.

More DNS

Now that chatmail has been deployed to the server, we need to add more DNS records. Thankfully, the chatmail devs made a script to tell us what is needed. I had to run a few rounds of this to get to the point that all required DNS records were available.

Run the command below until you no longer have missing DNS entries returned. I've included a couple examples of the output I encountered. If you want to preemptively add records, I've compiled a list of those I needed to create below.

./scripts/cmdeploy dns

Round 1:

> ./scripts/cmdeploy dns

WARNING: these recommended DNS entries are not set:

delta.chat.me.                     MX 10 delta.chat.me.
_mta-sts.delta.chat.me.            TXT "v=STSv1; id="
opendkim._domainkey.delta.chat.me. TXT "v=DKIM1;k=rsa;p=a-bunch-of-characters" "a-bunch-of-other-characters;s=email;t=s"

Round 2:

> ./scripts/cmdeploy dns

WARNING: these recommended DNS entries are not set:

delta.chat.me.                   TXT "v=spf1 a:delta.chat.me ~all"
_dmarc.delta.chat.me.            TXT "v=DMARC1;p=reject;adkim=s;aspf=s"
delta.chat.me.                   CAA 0 issue "letsencrypt.org;accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/0123456789"
_adsp._domainkey.delta.chat.me.  TXT "dkim=discardable"
_submission._tcp.delta.chat.me.  SRV 0 1 587 delta.chat.me.
_submissions._tcp.delta.chat.me. SRV 0 1 465 delta.chat.me.
_imap._tcp.delta.chat.me.        SRV 0 1 143 delta.chat.me.
_imaps._tcp.delta.chat.me.       SRV 0 1 993 delta.chat.me.

Summary of all required DNS records

Below are all the DNS records I ended up creating. As mentioned above, if you're using Cloudflare, set the proxy status to DNS only. You might be able to enable proxying for some of these, but I haven't tested any of them.

A

Name IPv4 address TTL
delta 199.52.201.123 Auto

CNAME

Name Target TTL
mta-sts.delta delta.chat.me Auto
www.delta delta.chat.me Auto

CAA

Name Flags TTL Tag CA domain name Notes
delta 0 Auto Only allow specific hostnames "letsencrypt.org;accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/0123456789" You must use the CA domain name provided by the output of the script

MX

Name Mail server TTL Priority
delta delta.chat.me Auto 10

SRV

Name Priority Weight TTL Port Target
_imaps._tcp.delta 0 1 Auto 993 delta.chat.me
_imap._tcp.delta 0 1 Auto 143 delta.chat.me
_submissions._tcp.delta 0 1 Auto 465 delta.chat.me
_submission._tcp.delta 0 1 Auto 587 delta.chat.me

TXT

Name TTL Content Notes
_adsp._domainkey.delta Auto "dkim=discardable"
delta Auto "v=spf1 a:delta.chat.me ~all"
_dmarc.delta Auto "v=DMARC1;p=reject;adkim=s;aspf=s"
_mta-sts.delta Auto "v=STSv1; id="
opendkim._domainkey.delta Auto "v=DKIM1;k=rsa;p=a-bunch-of-characters" "a-bunch-of-other-characters;s=email;t=s" Use the content output from the dns command

Test the setup

You can use the status and test deploys to check your setup:

./scripts/cmdeploy test
./scripts/cmdeploy status

Secure the server

We left a few security steps unfinished during our initial setup. We'll take this opportunity to make some of these changes. These will all be done on the remote server, so begin by ssh-ing into the server.

Firewall

We'll start with a few firewall rules using ufw. As a reminder, these need to be run as root or with sudo.

ufw default deny incoming
ufw default allow outgoing
ufw allow "Nginx Full"
ufw allow Postfix
ufw allow "Postfix SMTPS"
ufw allow "Postfix Submission"
ufw allow "Dovecot IMAP"
ufw allow "Dovecot Secure IMAP"
ufw allow OpenSSH
ufw enable

The OpenSSH firewall rule above, will allow connections to OpenSSH from anywhere. If you want to add a bit more security, you can limit the IP to your public IP with something like:

ufw allow from 1.2.3.4/32 to any app "OpenSSH"

or an IP block with:

ufw allow from 1.2.3.4/20 to any app "OpenSSH"

Be careful with these rules, though. If you don't have a static IP and your IP ends up outside the allowed range, you won't be able to SSH into the server. You can login via the web shell and fix the rules, but that's a pain.

Security updates

Make sure unattended-upgrades is installed and enabled.

apt update
apt install unattended-upgrades

Open the unattended-upgrades configuration: nano /etc/apt/apt.conf.d/50unattended-upgrades and make sure at least security updates are enabled. Below is the default configuration for Ubuntu, including security and distro upgrades.

Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}";
        "${distro_id}:${distro_codename}-security";
        // Extended Security Maintenance; doesn't necessarily exist for
        // every release and this system may not have it installed, but if
        // available, the policy for updates is such that unattended-upgrades
        // should also install from here by default.
        "${distro_id}ESMApps:${distro_codename}-apps-security";
        "${distro_id}ESM:${distro_codename}-infra-security";
//      "${distro_id}:${distro_codename}-updates";
//      "${distro_id}:${distro_codename}-proposed";
//      "${distro_id}:${distro_codename}-backports";
};

Optionally, you can have the machine reboot automatically by updating the following lines

//Unattended-Upgrade::Automatic-Reboot "false";
//Unattended-Upgrade::Automatic-Reboot-Time "02:00";

to something like

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

This will automatically reboot the machine at 2:00 AM local time, if required.

Next steps

Now that your chatmail service is up and running, you probably want to start using it. Rather than make this post any longer than it already is, see Getting started with Delta Chat for steps on creating, transferring, and backing up your account.

Speaking of backing up, you should be thinking of how you'll protect your and your users' data via backups of the service. I haven't yet setup a backup system beyond Linode's weekly backups, but am working on implementing a separate backup for the chatmail service.