Operations 27 min read

Build a Secure Self-Hosted Email Server on CentOS with Postfix, Dovecot, MySQL

Learn step‑by‑step how to set up a fully functional, self‑hosted email system on CentOS 7.9 using Postfix, Dovecot, MariaDB, OpenDKIM and Nginx, covering software installation, configuration files, database schema, TLS/SSL, DNS records, and webmail integration with Roundcube.

Open Source Linux
Open Source Linux
Open Source Linux
Build a Secure Self-Hosted Email Server on CentOS with Postfix, Dovecot, MySQL

1. Introduction

Why build your own mail system? Using a personal domain and a Linux server gives you full control, better security, and avoids reliance on third‑party providers.

2. Required Software & Environment

OS: CentOS 7.9 (minimal, SELinux and firewall disabled)

Packages: Postfix 2.10.1, Dovecot 2.2.10, MariaDB 5.5.52, OpenDKIM 2.11.0, Nginx 1.10.2, PHP 5.4.16, Roundcube WebMail 1.3.0

Domain: example.com Public IP: 1.1.1.1 Sub‑domain for mail:

mail.example.com

3. Install Packages

yum -y update && \
yum -y install epel-release && \
 yum -y install dovecot dovecot-mysql mariadb-server nginx opendkim php-fpm php-mbstring php-mysql php-xml postfix pypolicyd-spf tar wget

4. Configure MariaDB

Start and secure the database, then create a dedicated user and schema for the mail system.

systemctl start mariadb
mysql_secure_installation
CREATE USER 'mail_sys'@'localhost' IDENTIFIED BY 'mail_sys';
CREATE DATABASE mail_sys;
GRANT SELECT ON mail_sys.* TO 'mail_sys'@'localhost' IDENTIFIED BY 'mail_sys';
FLUSH PRIVILEGES;

Create tables for domains, users and aliases:

CREATE TABLE domains (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL);
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, domain_id INT NOT NULL, password VARCHAR(200) NOT NULL, email VARCHAR(200) NOT NULL, UNIQUE(email), FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE CASCADE);
CREATE TABLE aliases (id INT AUTO_INCREMENT PRIMARY KEY, domain_id INT NOT NULL, source VARCHAR(200) NOT NULL, destination VARCHAR(200) NOT NULL, FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE CASCADE);

5. Postfix Configuration

Backup the original config and replace /etc/postfix/main.cf with the following (adjust domain and certificate paths):

mydomain = example.com
myhostname = mail.example.com
mydestination = localhost
virtual_transport = lmtp:unix:private/dovecot-lmtp
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
virtual_mailbox_domains = mysql:/etc/postfix/mysql_mailbox_domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql_mailbox_maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql_alias_maps.cf
smtpd_tls_security_level = may
smtp_tls_security_level = may
smtpd_tls_cert_file = /etc/pki/tls/certs/cert.pem
smtpd_tls_key_file = /etc/pki/tls/private/key.pem

Update /etc/postfix/master.cf to enable LMTP and submission services (see source for full content).

6. Dovecot Configuration

Backup the original config and set up /etc/dovecot/dovecot.conf to load the conf.d files. Define mail location and namespaces in 10-mail.conf:

mail_location = maildir:/var/spool/mail/%d/%n
namespace inbox {
  inbox = yes
}

Configure authentication against MariaDB in 10-auth.conf and auth-sql.conf.ext:

auth_mechanisms = plain login
!include auth-sql.conf.ext
driver = sql
connect = host=localhost dbname=mail_sys user=mail_sys password=mail_sys
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM users WHERE email='%u';

Enable SSL in 10-ssl.conf (use your own cert/key).

7. OpenDKIM Setup

Create /etc/opendkim.conf and generate a key for your domain:

Syslog yes
UMask 002
OversignHeaders From
Socket inet:[email protected]
Domain example.com
KeyFile /etc/opendkim/keys/mail.private
Selector mail
RequireSafeKeys no
opendkim-genkey -D /etc/opendkim/keys/ -d example.com -s mail
chown -R opendkim:opendkim /etc/opendkim/keys/

Add DKIM signing to Postfix:

milter_protocol = 2
milter_default_action = accept
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = inet:127.0.0.1:8891

8. DNS Records

Configure the following records at your DNS provider (example uses DNSPod):

A record: @ → 1.1.1.1 MX record: @ → mail.example.com SPF TXT: v=spf1 mx -all DMARC TXT: v=DMARC1; p=reject DKIM TXT for selector mail (value taken from /etc/opendkim/keys/mail.txt)

9. Webmail (Roundcube) Installation

Download, extract and place Roundcube under /usr/share/roundcube:

wget https://github.com/roundcube/roundcubemail/releases/download/1.3.0/roundcubemail-1.3.0-complete.tar.gz
tar -xf roundcubemail-1.3.0-complete.tar.gz
mv roundcubemail-1.3.0 /usr/share/roundcube
chown -R apache:apache /usr/share/roundcube

Configure Nginx to serve Roundcube over HTTPS (replace domain and certificate paths):

server {
    listen 80;
    server_name mail.example.com;
    return 301 https://$server_name$request_uri;
}
server {
    listen 443 ssl http2;
    server_name mail.example.com;
    ssl_certificate "/etc/pki/tls/certs/cert.pem";
    ssl_certificate_key "/etc/pki/tls/private/key.pem";
    location / {
        root /usr/share/roundcube;
        index index.php;
    }
    location ~ \.php$ {
        root /usr/share/roundcube;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Create a MySQL user and database for Roundcube, then run the installer at https://mail.example.com/installer/ and disable it afterwards:

CREATE USER 'roundcube'@'localhost' IDENTIFIED BY 'roundcube';
CREATE DATABASE roundcube;
GRANT ALL ON roundcube.* TO 'roundcube'@'localhost' IDENTIFIED BY 'roundcube';
FLUSH PRIVILEGES;
chmod -R 000 /usr/share/roundcube/installer/

10. Testing

Send a test email from an external account (e.g., Gmail) to verify reception. Use mail‑tester.com to send a test message and check SPF, DKIM and DMARC results.

11. Optional Firewall Rules

Open the required ports (25, 465, 587, 993) for inbound traffic, e.g. with iptables:

iptables -A INPUT -p tcp -m multiport --dports 25,465,587,993 -j ACCEPT

12. Conclusion

The guide provides a complete, self‑hosted mail solution on CentOS, including secure TLS, DKIM signing, SPF/DMARC protection, and a webmail interface. While spam filtering is not covered, the setup offers a solid foundation for personal or small‑business email services.

Mail system diagram
Mail system diagram
Mail system diagram 2
Mail system diagram 2
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

LinuxpostfixSelf-hosteddovecotemail serverroundcube
Open Source Linux
Written by

Open Source Linux

Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.