Skip to content

chatmail-alpine/docker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

157 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

chatmail in docker

This guide will help you to setup a chatmail relay using only a couple of docker compose commands.

For general info about the purpose and architecture of chatmail relays, please see this documentation (mirrors: Codeberg, GitHub).

Requirements

  • Public IP address with non-restricted SMTP and IMAP ports
  • Registered domain name
  • 1 GB of RAM
  • 1 CPU core
  • ~10 GB of storage for ~a hundred active users
  • Docker Compose installed

Setup

Initial DNS

Please set the following DNS records, assuming chat.example.com is your domain and 1.2.3.4 is your IP (replace them correspondingly):

chat.example.com.          A      1.2.3.4

www.chat.example.com.      CNAME  chat.example.com
mta-sts.chat.example.com.  CNAME  chat.example.com

Configuration files

For convenience, let's create a separate directory:

cd
mkdir chatmail
cd chatmail

Download compose.yml and example chatmail.ini:

curl -fsSO https://git.dc09.xyz/chatmail/docker/raw/branch/main/compose.yml
curl -fsS -o chatmail.ini https://git.dc09.xyz/chatmail/docker/raw/branch/main/chatmail.example.ini

Alternatively, from mirrors:

Mirrors

Codeberg

curl -fsSO https://codeberg.org/chatmail-alpine/docker/raw/branch/main/compose.yml
curl -fsS -o chatmail.ini https://codeberg.org/chatmail-alpine/docker/raw/branch/main/chatmail.example.ini

GitHub

curl -fsSLO https://github.com/chatmail-alpine/docker/raw/refs/heads/main/compose.yml
curl -fsSL -o chatmail.ini https://github.com/chatmail-alpine/docker/raw/refs/heads/main/chatmail.example.ini

Open chatmail.ini and adjust parameters. You need to change mail_domain to your domain, other options can be left at their defaults.

Create a directory where chatmail relay stores all of its files:

mkdir instance

Getting certs

Note: see "Special cases" if you already have an ACME client and/or an HTTP server running on the host and want to replace the chatmail-provided one with it.

First, launch nginx only:

docker compose up -d nginx

Next, run certbot:

docker compose run --rm certbot

Answer a couple of question, and that's it, you received new TLS certificates for your chatmail.

Important:
Restart nginx so it will run with a different config with TLS enabled:

docker compose restart nginx

Start chatmail

docker compose up -d

Check logs, you shouldn't see any errors:

docker compose logs

Finish DNS setup

chat.example.com.  MX  10  chat.example.com.

(10 is a mail server priority)

_mta-sts.chat.example.com.  TXT  "v=STSv1; id=202604012111"

chat.example.com.           TXT  "v=spf1 a ~all"
_dmarc.chat.example.com.    TXT  "v=DMARC1;p=reject;adkim=s;aspf=s"

_adsp._domainkey.chat.example.com.  TXT  "dkim=discardable"

DKIM

Read a newly generated public DKIM key:

docker compose exec opendkim cat /etc/dkimkeys/opendkim.txt

You'll get something like:

opendkim._domainkey	IN	TXT	( "v=DKIM1; h=sha256; k=rsa; "
  "p=MIIBIj....uMRk"
  "r6WwhL....QAB" )  ; ----- DKIM key opendkim for chat.example.com

Copy the whole p= parameter value (it's split in two lines) and create a DNS record like this, pasting your p= value instead:

opendkim._domainkey.chat.example.com.  TXT  "v=DKIM1;k=rsa;p=MIIBIj...uMRkr6WwhL...QAB;s=email;t=s"

(also note the ;s=email;t=s in the end)

SRV

_submission._tcp.chat.example.com.   SRV  0  1  587  chat.example.com.
_submissions._tcp.chat.example.com.  SRV  0  1  465  chat.example.com.

_imap._tcp.chat.example.com.         SRV  0  1  143  chat.example.com.
_imaps._tcp.chat.example.com.        SRV  0  1  993  chat.example.com.

(0 is priority, 1 is weight, the third number is port)

Fine-grained config

You may want to modify lower-level chatmail components' configuration files and/or web pages templates.

In that case, you need to download the whole chatmail-docker repository, instead of only the two files (compose and ini).

git clone https://git.dc09.xyz/chatmail/docker.git chatmail
cd chatmail
Mirrors

Codeberg

git clone https://codeberg.org/chatmail-alpine/docker.git chatmail

GitHub

git clone https://github.com/chatmail-alpine/docker.git chatmail

In compose.yml, uncomment the two volumes for the generate service to overlay default templates with your changes.

Components' configs are in src/config.
Web pages are in src/web.
Other files are used only when building images and modifiying them gives no effect (though some of them can actually still be replaced by mounting volumes).

Special cases

Basically, you can modify your compose.yml whatever the way you want if you know what you're doing.

I already have certbot installed

Properly configuring TLS certs can be a bit tricky, here's how to do it when you want to manage certs from the outside.

Note: it may be better to issue certs for chatmail separately and leave the provided certbot configuration as is. Please check whether the second option "I already have nginx installed" suits your case.

First, run the generator script to initialize the directory tree:

docker compose run --rm generate

You have to add a deploy hook that your ACME client will run on every cert renewal to copy certs and reload chatmail services. For certbot, this can be done by creating and chmod +xing the following script in /etc/letsencrypt/renewal-hooks/deploy/chatmail.sh:

Script contents
#!/bin/sh

set -eu

cert_dir="$RENEWED_LINEAGE"
# or simply:
#cert_dir="/etc/letsencrypt/live/chat.example.com"

# replace to your instance directory!
target_dir="/home/user/chatmail/instance/config/tls"

tls_cert="$target_dir/cert.pem"
tls_key="$target_dir/key.pem"

echo "Running deploy hook for $cert_dir"

cp "$cert_dir/fullchain.pem" "$tls_cert"
cp "$cert_dir/privkey.pem" "$tls_key"
echo "Private key copied to $tls_key"

chown root: "$tls_cert" "$tls_key"
chmod 644 "$tls_cert"
chmod 600 "$tls_key"

echo "Reloading services"
touch "$target_dir/reload"

Run this deploy hook once to initially copy your certs to the required path:

RENEWED_LINEAGE="/etc/letsencrypt/live/chat.example.com" \
  /etc/letsencrypt/renewal-hooks/deploy/chatmail.sh

Now, comment out or remove the certbot: block from your compose.yml.

Restart nginx from chatmail compose if you started it before and proceed to the next steps.

I already have nginx installed

Note: see the provided nginx config as a reference (mirrors: Codeberg, GitHub).

Comment out or remove the nginx: block from your compose.yml.

web pages

Configure nginx to serve static files on chat.example.com, mta-sts.chat.example.com and www.chat.example.com from the webroot directory /home/user/chatmail/instance/web (assuming /home/user/chatmail is where you put the compose + ini configs and the instance directory).

newemail and iroh

Uncomment the ports: block for iroh-relay service in compose.yml to access iroh from your nginx on the host.

Reverse proxy these paths on chat.example.com:

nginx config snippet
location /new {
  if ($request_method = GET) {
    return 301 dcaccount:https://chat.example.com/new;
  }
  proxy_pass http://unix:/home/user/chatmail/instance/socket/newemail/actix.sock;
  proxy_http_version 1.1;
}

location /relay {
  proxy_pass http://127.0.0.1:3340;
  proxy_http_version 1.1;
  proxy_set_header Connection "upgrade";
  proxy_set_header Upgrade $http_upgrade;
}

location /relay/probe {
  proxy_pass http://127.0.0.1:3340;
  proxy_http_version 1.1;
}

location /generate_204 {
  proxy_pass http://127.0.0.1:3340;
  proxy_http_version 1.1;
}

certbot

If you use the chatmail-provided certbot, i. e. didn't follow the instructions above to replace it with your own ACME client and decided to issue certs for chatmail separately, you also need to configure your HTTP server to serve static files for the same hosts from the certbot webroot directory /home/user/chatmail/instance/data/certbot/web in case a path under /.well-known/acme-challenge/ is requested.

Note: the certbot webroot contains a .well-known directory, i. e. you have to set root, not an alias (alternatively, rewrite + alias, but why would you need such a complexity).

nginx config snippet
http {
  server {
    # ...
    location /.well-known/acme-challenge/ {
      root /home/user/chatmail/instance/data/certbot/web;
    }
  }
}

TLS certificate issued by the chatmail certbot is located in /home/user/chatmail/instance/config/tls/cert.pem and key.pem.

mail on port 443

Chatmail multiplexes https and smtps/imaps on the same port so relays remain accessible even when ports other than 443 are blocked on the client's side.

To do so, move all your virtual hosts (server{}s) to a local listen port or a unix socket, like this:

nginx config snippet
# Before
http {
  server {
    listen 443 ssl;
    server_name example.com;
    root /var/www/pages;
  }
}

# After
http {
  server {
    listen unix:/run/nginx/nginx.sock ssl;
    # or
    #listen 127.0.0.1:8443 ssl;
    server_name example.com;
    root /var/www/pages;
  }
}

...and then create a stream server proxying connections based on matched ALPN:

nginx config snippet
stream {
  map $ssl_preread_alpn_protocols $proxy {
    default unix:/run/nginx/nginx.sock;
    # or, if you chose to use a local port instead
    #default 127.0.0.1:8443;
    ~\bsmtp\b 127.0.0.1:465;
    ~\bimap\b 127.0.0.1:993;
  }

  server {
    listen 443;
    listen [::]:443;
    ssl_preread on;
    proxy_pass $proxy;
  }
}

Alternatively, if you really don't want to modify listen directives in your nginx config, you may (but shouldn't) remove the support for 443 multiplexing. Open src/web/.well-known/autoconfig/mail/config-v1.1.xml and delete one incomingServer and one outgoingServer blocks where port is set to 443.

About

Docker images + Compose for all the chatmail components tied together

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors