Files
2026-09-18 12:24:08 +03:00

6.0 KiB

EternityMail

Docker Compose deployment for Stalwart Mail and Roundcube.

Requirements

  • Docker Engine with the Compose plugin
  • A Linux host for the production deployment
  • DNS records pointing the mail hostname to the server
  • The ep-roundcube-skin repository available as a sibling directory if the custom skin is enabled

Configuration

Create the real environment file from the template:

cp .env.example .env

Edit .env and set production values, especially:

  • MAIL_HOSTNAME and MAIL_DOMAIN
  • RC_DB_PASSWORD
  • RC_DB_ROOT_PASSWORD
  • RC_DES_KEY
  • STALWART_RECOVERY_ADMIN

The real .env file is ignored by Git. Do not commit credentials or recovery settings.

Roundcube uses MAIL_HOSTNAME for IMAP and SMTP submission by default. To connect Roundcube to Stalwart by IP instead, add ROUNDCUBE_IMAP_HOST=<ip-address> and ROUNDCUBE_SMTP_HOST=<ip-address> to .env. These change only Roundcube's IMAP and SMTP endpoints; MAIL_HOSTNAME remains the Stalwart hostname and Docker network alias.

For a local Stalwart test installation using its generated self-signed certificate, set ROUNDCUBE_ALLOW_SELF_SIGNED_CERT=true in .env. This disables certificate verification for Roundcube's IMAP and SMTP connections and must be set to false after configuring a trusted Stalwart certificate.

Generate a DES key

On Linux or macOS:

chmod +x scripts/generate-des-key.sh
scripts/generate-des-key.sh

On Windows PowerShell:

.\scripts\generate-des-key.ps1

Put the generated 24-character value in RC_DES_KEY in .env.

Persistent Stalwart data

Stalwart configuration, mail, and certificates are stored in Docker-managed volumes. This avoids host filesystem ownership problems after Docker Desktop or WSL restarts. The stalwart-data-init service assigns the ownership Stalwart requires before it starts.

Do not use docker compose down --volumes or docker volume rm for this project unless you intend to permanently delete Stalwart's configuration and mail data.

To protect against laptop loss, disk failure, or a Docker Desktop reset, back up the three eternitymail-stalwart-* volumes to storage outside Docker Desktop. Docker volumes protect data across normal container recreation, not a destroyed Docker data disk.

The legacy Linux bind-mount preparation command applies only to deployments which still use DATA_ROOT bind mounts:

chmod +x scripts/setup-data-dirs.sh
sudo ./scripts/setup-data-dirs.sh

The script uses DATA_ROOT from .env when it is exported in the shell; otherwise it defaults to /opt/eternitymail. To use the value from .env directly, run the setup command with it loaded or pass the path explicitly:

sudo DATA_ROOT=/opt/eternitymail ./scripts/setup-data-dirs.sh

Custom Roundcube skin

The default configuration expects the skin at:

../ep-roundcube-skin/eternity

relative to this repository. Override the location in .env with ROUNDCUBE_SKIN_PATH if needed. The skin directory is mounted read-only and selected with ROUNDCUBE_SKIN_NAME.

The bundled roundcube-config/eternity-logo.php override sets the login and mailbox logos to the Eternity skin's images/logo.svg through Roundcube's static.php asset endpoint. This is required because Eternity inherits Elastic's templates, which would otherwise display Elastic's default logo. Keep this file and its mount in docker-compose.yml when using the Eternity skin.

Start and stop

Validate the rendered configuration:

docker compose config --quiet

Start the services:

docker compose up -d

View service status and logs:

docker compose ps
docker compose logs -f stalwart

Stop the services without deleting persistent data:

docker compose down

Persistent data is stored under DATA_ROOT in the stalwart, roundcube-db, and roundcube-config directories.

Backup, restore, and server migration

Backups include Stalwart configuration, certificates, mailboxes, Roundcube's database/configuration, .env, and docker-compose.yml. The backup stops the mail services briefly so the RocksDB and MariaDB files are consistent, then starts them again.

On Linux, create a backup outside Docker Desktop or the server's Docker data disk:

chmod +x scripts/backup-server.sh scripts/restore-server.sh
./scripts/backup-server.sh /mnt/backup/eternitymail

On Windows PowerShell:

.\scripts\backup-server.ps1 -Destination D:\Backups\EternityMail

Restore that backup to Docker Desktop with:

.\scripts\restore-server.ps1 -Archive D:\Backups\EternityMail\eternitymail-<timestamp>.tar.gz

Copy the resulting .tar.gz archive, this repository, and the ep-roundcube-skin checkout to the new Linux server. Install Docker Engine with the Compose plugin, then restore from the repository root:

sudo ./scripts/restore-server.sh /mnt/backup/eternitymail/eternitymail-<timestamp>.tar.gz
docker compose ps

Restore refuses to replace an existing deployment unless --force (Linux) or -Force (PowerShell) is supplied. That option stops the stack and permanently replaces its Stalwart volumes and Roundcube bind-mount data. Keep the same .env from the archive, particularly RC_DES_KEY, passwords, hostname, and recovery administrator setting. Before moving production traffic, update the new server's DNS, firewall, and TLS configuration, then verify IMAPS and SMTP.

Network ports

The host bindings are configurable in .env:

  • SMTP: STALWART_SMTP_PORT (default 25)
  • Submission: STALWART_SUBMISSION_PORT (default 587)
  • IMAPS: STALWART_IMAPS_PORT (default 993)
  • Stalwart administration: STALWART_ADMIN_BIND and STALWART_ADMIN_PORT (defaults 127.0.0.1:8081); set STALWART_ADMIN_BIND= to listen on all host interfaces
  • Roundcube: ROUNDCUBE_BIND and ROUNDCUBE_PORT (defaults 127.0.0.1:8091); set ROUNDCUBE_BIND= to listen on all host interfaces

The Stalwart and Roundcube containers communicate over the private eternitymail Docker network.