Skip to content

Deploy iRedMail

Purpose: Self-Hosted Open-Source email server that can be setup in minutes, and is enterprise-grade if upgraded with an iRedAdmin-Pro license.

Assumptions

It is assumed you are running at least Rocky Linux 9.3. While you can use CentOS Stream, Alma, Debian, Ubuntu, FreeBSD, and OpenBSD, the more enterprise-level sections of my homelab are built on Rocky Linux.

iRedMail / iRedAdmin-Pro Version Mismatching

This document assumes you are deploying iRedMail 1.6.8, which at the time of writing, coincided with iRedAdmin-Pro 5.5. If you are not careful, you may end up with mismatched versions down the road as iRedMail keeps getting updates. Due to how you have to pay for a license in order to get access to the original iRedAdmin-Pro-SQL repository data, if a newer version of iRedAdmin-Pro comes out after February 2025, this document may not account for that, leaving you on an older version of the software. This is unavoidable if you want to avoid paying $500/year for licensing this software.

Overview

The instructions below are specific to my homelab environment, but can be easily ported depending on your needs. This guide also assumes you want to operate a PostgreSQL-based iRedMail installation. You can follow along with the official documentation on Installation as well as DNS Record Configuration if you want more detailed explanations throughout the installation process.

Configure FQDN

Ensure the FQDN of the server is correctly set in /etc/hostname. The /etc/hosts file will be automatically injected using the FQDN from /etc/hostname in a script further down, don't worry about editing it.

Disable SELinux

iRedMail doesn't work with SELinux, so please disable it by setting below value in its config file /etc/selinux/config. After server reboot, SELinux will be completely disabled.

# Elevate to Root User
sudo su

# Disable SELinux
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config # (1)
setenforce 0

  1. If you prefer to let SELinux prints warnings instead of enforcing, you can set this value instead: SELINUX=permissive

iRedMail Installation

Set Domain and iRedMail Version

Start by connecting to the server / VM via SSH, then set silent deployment variables below.

# Define some deployment variables.  
VERSION="1.6.8" # (1)
MAIL_DOMAIN="bunny-lab.io" # (2)

  1. This is the version of iRedMail you are deploying. You can find the newest version on the iRedMail Download Page.
  2. This is the domain suffix that appears after mailbox names. e.g. [email protected] would use a domain value of bunny-lab.io.

You will then proceed to bootstrap a silent unattended installation of iRedMail. (I've automated as much as I can to make this as turn-key as possible). Just copy/paste this whole thing into your terminal and hit ENTER.

Storage Space Requirements

You absolutely need to ensure that /var/vmail has a lot of space. At least 16GB. This is where all of your emails / mailboxes / a lot of settings will be. If possible, create a second physical/virtual disk specifically for the /var partition, or specifically for /var/vmail at minimum, so you can expand it over time if necessary. LVM-based provisioning is recommended but not required.

Install iRedMail

# Automatically configure the /etc/hosts file to point to the server listed in "/etc/hostname".
sudo sed -i "1i 127.0.0.1 $(cat /etc/hostname) $(cut -d '.' -f 1 /etc/hostname) localhost localhost.localdomain localhost4 localhost4.localdomain4" /etc/hosts

# Check for Updates in the Package Manager
yum update -y

# Install Extra Packages for Enterprise Linux
dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm

# Download the iRedMail binaries and extract them
cd /root
curl https://codeload.github.com/iredmail/iRedMail/tar.gz/refs/tags/$VERSION -o iRedMail-$VERSION.tar.gz
tar zxf iRedMail-$VERSION.tar.gz

# Create the unattend config file for silent deployment.  This will automatically generate random 32-character passwords for all of the databases.
(echo "export STORAGE_BASE_DIR='/var/vmail'"; echo "export WEB_SERVER='NGINX'"; echo "export BACKEND_ORIG='PGSQL'"; echo "export BACKEND='PGSQL'"; for var in VMAIL_DB_BIND_PASSWD VMAIL_DB_ADMIN_PASSWD MLMMJADMIN_API_AUTH_TOKEN NETDATA_DB_PASSWD AMAVISD_DB_PASSWD IREDADMIN_DB_PASSWD RCM_DB_PASSWD SOGO_DB_PASSWD SOGO_SIEVE_MASTER_PASSWD IREDAPD_DB_PASSWD FAIL2BAN_DB_PASSWD PGSQL_ROOT_PASSWD DOMAIN_ADMIN_PASSWD_PLAIN; do echo "export $var='$(openssl rand -base64 48 | tr -d '+/=' | head -c 32)'"; done; echo "export FIRST_DOMAIN='$MAIL_DOMAIN'"; echo "export USE_IREDADMIN='YES'"; echo "export USE_SOGO='YES'"; echo "export USE_NETDATA='YES'"; echo "export USE_FAIL2BAN='YES'"; echo "#EOF") > /root/iRedMail-$VERSION/config

# Make Config Read-Only
chmod 400 /root/iRedMail-$VERSION/config

# Set Environment Variables for Silent Deployment
cd /root/iRedMail-$VERSION

# Deploy iRedMail via the Install Script
AUTO_USE_EXISTING_CONFIG_FILE=y \
    AUTO_INSTALL_WITHOUT_CONFIRM=y \
    AUTO_CLEANUP_REMOVE_SENDMAIL=y \
    AUTO_CLEANUP_REPLACE_FIREWALL_RULES=y \
    AUTO_CLEANUP_RESTART_FIREWALL=n \
    AUTO_CLEANUP_REPLACE_MYSQL_CONFIG=y \
    bash iRedMail.sh

When the installation is completed, take note of any output it gives you for future reference. Then reboot the server to finalize the server installation.

reboot

Automatically-Generated Postmaster Password

When you deploy iRedMail, it will give you a username and password for the postmaster account. If you accidentally forget to document this, you can log back into the server via SSH and see the credentials at /root/iRedMail-$VERSION/iRedMail.tips. This file is critical and contains passwords and DNS information such as DKIM record information as well.

Networking Configuration

Nested Reverse Proxy Configuration

In my homelab environment, I run Traefik reverse proxy in front of everything, which includes the NGINX reverse proxy that iRedMail creates. In my scenario, I have to make some custom adjustments to the reverse proxy dynamic configuration data to ensure it will step aside and let the NGINX reverse proxy inside of iRedMail handle everything, including handling its own SSL termination with Let's Encrypt.

tcp:
  routers:
    mail-tcp-router:
      rule: "HostSNI(`mail.bunny-lab.io`)"
      entryPoints: ["websecure"]
      service: mail-nginx-service
      tls:
        passthrough: true

  services:
    mail-nginx-service:
      loadBalancer:
        servers:
          - address: "192.168.3.13:443"

Let's Encrypt ACME Certbot

At this point, we want to set up automatic Let's Encrypt SSL termination inside of iRedMail so we don't have to manually touch this in the future.

Generate SSL Certificate

# Download the Certbot
sudo apt update
sudo apt install -y certbot
sudo certbot certonly --webroot -w /var/www/html -d mail.bunny-lab.io

# Set up Symbolic Links (Where iRedMail Expects Them)
sudo mv /etc/ssl/certs/iRedMail.crt{,.bak}
sudo mv /etc/ssl/private/iRedMail.key{,.bak}
sudo ln -s /etc/letsencrypt/live/mail.bunny-lab.io/fullchain.pem /etc/ssl/certs/iRedMail.crt
sudo ln -s /etc/letsencrypt/live/mail.bunny-lab.io/privkey.pem /etc/ssl/private/iRedMail.key

# Restart iRedMail Services
sudo systemctl restart postfix dovecot nginx
# Download the Certbot
sudo yum install -y epel-release
sudo yum install -y certbot
sudo certbot certonly --webroot -w /var/www/html -d mail.bunny-lab.io

# Set up Symbolic Links (Where iRedMail Expects Them)
sudo mv /etc/pki/tls/certs/iRedMail.crt{,.bak}
sudo mv /etc/pki/tls/private/iRedMail.key{,.bak}
sudo ln -s /etc/letsencrypt/live/mail.bunny-lab.io/fullchain.pem /etc/pki/tls/certs/iRedMail.crt
sudo ln -s /etc/letsencrypt/live/mail.bunny-lab.io/privkey.pem /etc/pki/tls/private/iRedMail.key

# Restart iRedMail Services
sudo systemctl restart postfix dovecot nginx

Configure Automatic Renewal

To automate the renewal process, set up a cron job that runs the certbot renew command regularly. This command will renew certificates that are due to expire within 30 days.

Open the crontab editor with the following command:

sudo crontab -e

Add the following line to run the renewal process daily at 3:01 AM:

1 3 * * * certbot renew --post-hook 'systemctl restart postfix dovecot nginx'

DNS Records

Now you need to set up DNS records in Cloudflare (or the DNS Registrar you have configured) so that the mail server can be found and validated.

Type Name Content Proxy Status TTL
MX bunny-lab.io mail.bunny-lab.io DNS Only Auto
TXT bunny-lab.io "v=spf1 include:mail.bunny-lab.io ~all" DNS Only Auto
TXT dkim._domainkey v=DKIM1; p=IREDMAIL-DKIM-VALUE DNS Only 1 Hour
TXT _dmarc "v=DMARC1; p=reject; pct=100; rua=mailto:postmaster@bunny-lab.io; ruf=mailto:postmaster@bunny-lab.io" DNS Only Auto

Port Forwarding

Lastly, we need to set up port forwarding to open the ports necessary for the server to send and receive email.

Protocol Port Destination Server Description
TCP 995 192.168.3.13 POP3 service: port 110 over STARTTLS
TCP 993 192.168.3.13 IMAP service: port 143 over STARTTLS
TCP 587 192.168.3.13 SMTP service: port 587 over STARTTLS
TCP 25 192.168.3.13 SMTP (Email Server-to-Server Communication)

Install iRedAdmin-Pro

When it comes to adding extra features, start by copying the data from this Bunny Lab repository to the following folder by running these commands first:

# Stop the iRedMail Services
sudo systemctl stop postfix dovecot nginx

# Grant Temporary Access to the iRedAdmin Files and Folders
sudo chown nicole:nicole -R /opt/www/iRedAdmin-2.5

# Copy the data from the repository mentioned above into this folder, merging identical folders and files.  Feel free to use your preferred file transfer tool tool / method (e.g. MobaXTerm / WinSCP).

# Change permissions back to normal
sudo chown iredadmin:iredadmin -R /opt/www/iRedAdmin-2.5

# Reboot the Server
sudo reboot

Activate iRedAdmin-Pro

At this point, if you want to use iRedAdmin-Pro, you either have a valid license key, or you adjust the python function responsible for checking license keys to bypass the check, effectively forcing iRedAdmin to be activated. In this instance, we will be forcing activation by adjusting this function, seen below.

There is someone else who outlined all of these changes, and additional (aesthetic) ones, like removing the renew license button from the license page, but the core functionality is seen below. If you want to see the original repository this was inspired from, it can be found Here

# Take permission of the python script
sudo chown nicole:nicole /opt/www/iRedAdmin-2.5/libs/sysinfo.py
/opt/www/iRedAdmin-2.5/libs/sysinfo.py
def get_license_info():
if len(__id__) != 32:
    web.conn_iredadmin.delete("updatelog")
    session.kill()
    raise web.seeother("/login?msg=INVALID_PRODUCT_ID")

params = {
    "v": __version__,
    "f": __id__,
    "lang": settings.default_language,
    "host": get_hostname(),
    "backend": settings.backend,
    "webmaster": settings.webmaster,
    "mac": ",".join(get_all_mac_addresses()),
}

url = "https://lic.iredmail.org/check_version/licenseinfo/" + __id__ + ".json"
url += "?" + urllib.parse.urlencode(params)

try:
    urlopen = __get_proxied_urlopen()
    _json = urlopen(url).read()
    lic_info = json.loads(_json)
    lic_info["id"] = __id__
    return True, lic_info
except Exception as e:
    return False, web.urlquote(e)
/opt/www/iRedAdmin-2.5/libs/sysinfo.py
def get_license_info():
return True, {
    "status": "active",
    "product": "iRedAdmin-Pro-SQL",
    "licensekey": "forcefully-open-source",
    "upgradetutorials": "https://docs.iredmail.org/iredadmin-pro.releases.html",
    "purchased": "Never",
    "contacts": "[email protected]",
    "latestversion": "5.5",
    "expired": "Never",
    "releasenotes": "https://docs.iredmail.org/iredadmin-pro.releases.html",
    "id": __id__
}
# Revert permission of the python script
sudo chown iredadmin:iredadmin /opt/www/iRedAdmin-2.5/libs/sysinfo.py

# Reboot the Server (To be safe)
sudo reboot

Successful Activation

At this point, if you navigate to the iRedAdmin-Pro License Page you should see the server is activated successfully.