Installation Guide

System Requirements

Crymap is designed to run on FreeBSD and Linux. It probably works on the other BSDs, but is not tested on them. Windows is not supported and most likely never will be since its filesystem is incompatible with Crymap’s requirements on many fronts.

The host file system must support symlinks and hard links, be case-sensitive, and either be non-normalising or use NFC normalisation. There must not be mount points inside any user directory. Remote file systems like NFS are supported if they provide sufficient consistency guarantees, but Crymap is not specifically designed to work with them, and IDLE notifications will only work properly if all Crymap instances for a given user are run on the same host.

When run on a single-CPU host or with appropriate tuning on a multi-CPU host, each Crymap instance typically only consumes a few MB of RAM. However, do be aware that Crymap is a one-process-per-connection system.

Crymap generally only holds at most a few dozen file handles open at any given time.

Installation

Crymap requires having the OpenSSL libraries installed. On Debian/Ubuntu, you can get them with apt install openssl. FreeBSD has the required libraries in the base distribution. (There is a way to cause OpenSSL to be built along with Crymap and statically linked, but this is not recommended since you won’t be able to get OpenSSL updates with your OS and this process is not described in this manual.)

Each [https://github.com/AltSysrq/crymap/releases/](release of Crymap) has pre-built binaries for AMD64 Debian and FreeBSD. Simply download the appropriate one of these and save it in a place you consider appropriate; for example (# means “as root”):

# cp crymap-$version-$os-amd64 /usr/local/bin/crymap
# chmod a=rx /usr/local/bin/crymap

If you do not want to use the pre-built binary or need to run on a different OS or architecture, you need to build Crymap from source. This requires having Rust installed, which you can get through rustup.

The easiest way to build Crymap is to get it with cargo:

$ cargo install crymap
# cp ~yourusername/.cargo/bin/crymap /usr/local/bin/crymap

You can also clone the repository directly:

$ git clone git@github.com:altsysrq/crymap
$ cd crymap
$ cargo build --release
# cp target/release/crymap /usr/local/bin/crymap

Initial System Setup

First, make sure you have valid SSL certificates for your domain. A full explanation of how to do this is beyond the scope of this document, but Let’s Encrypt is a good place to start if you are new to this.

All files used by Crymap are reachable from (though not necessarily “in”) a directory referred to as the “Crymap root”. By default, this is either /etc/crymap or /usr/local/etc/crymap (whichever exists); you can use something else, but if you do so, you must pass --root to all crymap server commands to tell Crymap where its data is. For this tutorial, we’ll use /usr/local/etc/crymap as the root.

Start by creating the Crymap root directory. The files we’re setting up below shouldn’t be modified in normal operation, so they should be owned by root.

# mkdir /usr/local/etc/crymap

Next, we create Crymap’s system configuration file, which is a file named crymap.toml under the Crymap root. A minimal configuration example is shown below.

# /usr/local/etc/crymap/crymap.toml
[tls]
# The path to your X509 private key. The example here would be correct for
# a FreeBSD system at `example.org` using Let's Encrypt with the default
# configuration.
private_key = "/usr/local/etc/letsencrypt/live/example.org/privkey.pem"
# The path to the full X509 certificate chain.
certificate_chain = "/usr/local/etc/letsencrypt/live/example.org/fullchain.pem"

(Yes, that’s all there is to the required configuration.)

Before we go further, we need to decide what style of deployment we’re going to do. Crymap supports three general patterns:

  • UNIX-style deployment, in which each Crymap user corresponds to a UNIX user on the host system and owns their Crymap files.

  • Simple black box deployment, where Crymap users are unrelated to UNIX users, and all Crymap data is owned by a dedicated UNIX account. Crymap is always run under that UNIX account.

  • Two-step black box deployment. As above, but Crymap is run as root and then allowed to drop privileges once it no longer needs them. This requires more work to set up but means that the dedicated Crymap user doesn’t need permission to read SSL certificates and the like. This chapter won’t talk about this approach; simply go through the setup for the simple black box deployment, then refer to the configuration reference to see what to change.

If doing a black box deployment, set up the dedicated Crymap user now. Below, we’ll assume the user has name crymap and group mail, but of course that will vary with your system.

The next step is to create the users directory.

If doing a UNIX-style deployment, the user’s mail will typically be stored in their home directory. This means that users will not actually contain the data and we can just make it a normal directory.

# mkdir /usr/local/etc/crymap/users

On a black-box deployment, the user data will end up under whatever directory we create, and we don’t really want to be storing data under /etc. Thus, we will create the users directory elsewhere and symlink it from the nominal location. In this example, we store users under /srv/crymap-users.

# mkdir -m 750 /srv/crymap-users
# chown crymap:mail /srv/crymap-users
# ln -s /srv/crymap-users /usr/local/etc/crymap/users

To see if your configuration so far is good, try running crymap serve serve-imaps under the same UNIX account you intend using in the real deployment. If you get the message stdin and stdout must not be a terminal, it means the configuration is valid and Crymap was ready to serve network traffic.

We won’t create any users just yet.

Running Crymap in IMAPS mode

Crymap does not run as a daemon. Instead, it uses a one-process-per-connection model in which some other process listens for connections and spawns Crymap processes as connections arrive. There are a number of options here, including xinetd and systemd. Here, we will use traditional inetd, available as the package openbsd-inetd on Debian and part of the base FreeBSD installation.

Arranging for Crymap to be run by inetd is just a matter of adding two lines to /etc/inetd.conf and then restarting inetd:

imaps   stream  tcp     nowait  root    /usr/local/bin/crymap   crymap server serve-imaps
imaps	stream  tcp6    nowait  root    /usr/local/bin/crymap   crymap server serve-imaps

If setting up a simple black box deployment, replace root with whatever user you want to run Crymap as.

Note the second occurrence of crymap in the command line is because inetd requires the configuration to specify the usually implicit argv[0] explicitly.

Do not add entries for the imap4 service. Crymap does not support the obsolete cleartext+STARTTLS mechanism on the IMAP4 port 143.

To test whether this setup works, run crymap remote test --trace --host=localhost. (You can of course run from another system, in which case pass the server’s host name to --host.) If successful, you should see some IMAP protocol traces and receive a prompt for a password. Of course, since no users have been created yet, it is not possible to log in, so simply cancel once it gets that far.

Creating a User

User creation is done with the crymap server user add command. By default, it generates a random password for the new user; --prompt-password can be given to input a password on the terminal instead. Refer to the user guide to see how to change the password after the account has been created.

On a UNIX-style setup, this command should be run as root, and you’ll usually want to give the path to the user data explicitly.

# crymap server user add jsmith ~jsmith/crymap-mail

On a black box setup, this command should be run as the Crymap user, and if your users directory is symlinked to a location outside of /etc, you can leave the user directory off to simply store the user data inside users.

$ crymap server user add jsmith

With that done, you should be able to test logging in as the new user:

$ crymap remote test --host=localhost --user=jsmith

It is also possible at this point to connect your favourite email application to Crymap, though you can’t receive email just yet.

Configuring Mail Delivery

Since Crymap does not provide an SMTP solution, it must be integrated with a third party application to accept incoming mail. Crymap currently offers two ways to do this integration:

  • LMTP. LMTP is a variant of SMTP which is suitable for the final step in the mail delivery process. LMTP is robust, can correctly handle binary payloads, and can be more efficient, but is inflexible in that all messages are delivered to INBOX and without flags.

  • UNIX MDA. This is more flexible than LMTP as it can be made to deliver to arbitrary mailboxes in a user’s account and to set flags on new messages. In traditional UNIX setups, users can also invoke Crymap in as an MDA from their .forward file. Its main disadvantages are that it is less robust against errors, and because UNIX MDAs are typically passed the message with all line endings converted to UNIX line endings, Crymap must convert the line endings back, which will destroy binary content.

The instructions here are for LMTP. Refer to crymap server deliver --help for more information on using Crymap as an MDA. This section also contains concrete examples of using OpenSMTPD; if you are using a different SMTP daemon, you will need to refer to its documentation.

First, we need to set something up to run Crymap in LMTP mode. This works essentially the same as how we set up IMAPS, except here we don’t want the server to be accessible to anyone in the world. There’s two ways to do that:

  • Configure inetd, etc, to only listen on localhost.

  • Use a UNIX socket. This is what we do in this example, since it is possible to set finer-grained permissions.

Here is an example inetd configuration for a UNIX-style deployment:

:root:wheel:666:/var/run/lmtp.sock stream tcp nowait root /usr/local/bin/crymap crymap server serve-lmtp

Notes:

  • Notice this uses serve-lmtp instead of serve-imaps at the end.

  • root:wheel would be written root:root on typical Linux installations.

  • As with IMAPS, for a simple black box deployment, you would configure it to run under the Crymap user and not root.

  • This example allows anyone with shell access to open the LMTP socket and deliver mail (due to the 666 permission). To prevent that, you can give the socket a different owner and less permissive permissions. But to start with, it is probably best to keep it simple so there are fewer things to debug.

Crymap has a number of configurable options for LMTP. The defaults are fine for simple installations, but you may want to have a look at the configuration reference.

You can use socat to see if LMTP is working:

$ socat STDIO UNIX:/var/run/lmtp.sock
220 yourhostname crymap 1.0.0 LMTP ready
^C

Finally, you need to configure your SMTP server to deliver mail through LMTP. For OpenSMTPD, your smtpd.conf file might contain something like this:

action "local_mail" lmtp "/var/run/lmtp.sock"
match from any for domain "lin.gl" action "local_mail"
match for local action "local_mail"

After that, all that’s left to test is to send the user an email and see if it shows up!

Troubleshooting

By default, Crymap logs to syslog under the “mail” utility. When Crymap is not run from a terminal, this means its logs should end up someplace like /var/log/maillog or /var/log/mail.log.

In certain cases of severe misconfiguration (for example, by passing invalid parameters in inetd.conf), Crymap may instead print an error on standard error and exit. Where these messages end up depends on what you are using to run Crymap. The output might be in a system log like /var/log/messages, or it could be getting sent over the socket. To check for the latter case, you can run a command like socat STDIO TCP:localhost:993 to see if anything shows up.