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:
- This is a communication platform that you, presumably, want to be reliable, so you should put it somewhere that will be reliable.
- 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, addsudo
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.