1555 lines
28 KiB
Markdown
Executable File
1555 lines
28 KiB
Markdown
Executable File
---
|
|
id: Complete Mail Server Setup Guide
|
|
aliases: []
|
|
tags: []
|
|
---
|
|
|
|
# Complete Mail Server Setup Guide - Arch Linux Edition
|
|
|
|
## Postfix + Dovecot + MySQL + Notmuch + Encryption on Arch Linux LXC
|
|
|
|
This is the Arch Linux version of the complete mail server setup.
|
|
|
|
---
|
|
|
|
## Part 1: Proxmox LXC Container Setup for Arch Linux
|
|
|
|
### Download Arch Linux Template
|
|
|
|
In Proxmox shell:
|
|
|
|
```bash
|
|
pveam update
|
|
pveam available | grep arch
|
|
pveam download local archlinux-base_20231118-1_amd64.tar.zst
|
|
```
|
|
|
|
Or download manually from: https://uk.lxd.images.canonical.com/images/archlinux/current/amd64/default/
|
|
|
|
### Create the LXC Container
|
|
|
|
In Proxmox UI:
|
|
|
|
- **CT ID**: Choose available ID
|
|
- **Template**: archlinux-base
|
|
- **Disk**: 20GB minimum
|
|
- **CPU**: 2 cores
|
|
- **RAM**: 2GB minimum
|
|
- **Network**: Bridge, static IP (e.g., 192.168.1.100)
|
|
- **Unprivileged**: Yes
|
|
- **Features**: `nesting=1` (if you want Docker option later)
|
|
|
|
Start the container and note the IP address.
|
|
|
|
### Initial Container Setup
|
|
|
|
SSH into your Arch LXC container:
|
|
|
|
```bash
|
|
# Initialize pacman keyring (Arch specific)
|
|
pacman-key --init
|
|
pacman-key --populate archlinux
|
|
|
|
# Update system
|
|
pacman -Syu --noconfirm
|
|
|
|
# Install essential tools
|
|
pacman -S --noconfirm base-devel vim wget curl git sudo openssh
|
|
|
|
# Set hostname
|
|
hostnamectl set-hostname mail.example.com
|
|
echo "192.168.1.100 mail.example.com mail" >> /etc/hosts
|
|
|
|
# Enable time sync
|
|
systemctl enable --now systemd-timesyncd
|
|
```
|
|
|
|
### Configure Locale
|
|
|
|
```bash
|
|
# Uncomment your locale in /etc/locale.gen
|
|
vim /etc/locale.gen
|
|
# Uncomment: en_US.UTF-8 UTF-8
|
|
|
|
# Generate locale
|
|
locale-gen
|
|
|
|
# Set locale
|
|
echo "LANG=en_US.UTF-8" > /etc/locale.conf
|
|
```
|
|
|
|
---
|
|
|
|
## Part 2: MySQL/MariaDB Database Setup
|
|
|
|
### Install MariaDB
|
|
|
|
```bash
|
|
pacman -S --noconfirm mariadb mariadb-clients
|
|
```
|
|
|
|
### Initialize MariaDB
|
|
|
|
```bash
|
|
# Initialize the database
|
|
mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql
|
|
|
|
# Start and enable MariaDB
|
|
systemctl enable --now mariadb
|
|
|
|
# Secure installation
|
|
mysql_secure_installation
|
|
```
|
|
|
|
During secure installation:
|
|
|
|
- Set root password: Yes (choose strong password)
|
|
- Remove anonymous users: Yes
|
|
- Disallow root login remotely: Yes
|
|
- Remove test database: Yes
|
|
- Reload privilege tables: Yes
|
|
|
|
### Create Mail Database and Tables
|
|
|
|
```bash
|
|
mysql -u root -p
|
|
```
|
|
|
|
In MySQL prompt:
|
|
|
|
```sql
|
|
CREATE DATABASE mailserver CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
|
|
CREATE USER 'mailuser'@'localhost' IDENTIFIED BY '1ChagemaiL';
|
|
|
|
GRANT ALL PRIVILEGES ON mailserver.* TO 'mailuser'@'localhost';
|
|
|
|
FLUSH PRIVILEGES;
|
|
|
|
USE mailserver;
|
|
|
|
-- Domains table
|
|
CREATE TABLE IF NOT EXISTS virtual_domains (
|
|
id INT NOT NULL AUTO_INCREMENT,
|
|
name VARCHAR(50) NOT NULL,
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
-- Users table
|
|
CREATE TABLE IF NOT EXISTS virtual_users (
|
|
id INT NOT NULL AUTO_INCREMENT,
|
|
domain_id INT NOT NULL,
|
|
password VARCHAR(200) NOT NULL,
|
|
email VARCHAR(120) NOT NULL,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY email (email),
|
|
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
-- Aliases table
|
|
CREATE TABLE IF NOT EXISTS virtual_aliases (
|
|
id INT NOT NULL AUTO_INCREMENT,
|
|
domain_id INT NOT NULL,
|
|
source VARCHAR(100) NOT NULL,
|
|
destination VARCHAR(100) NOT NULL,
|
|
PRIMARY KEY (id),
|
|
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
|
-- Add your domain
|
|
INSERT INTO virtual_domains (name) VALUES ('liphlink.xyz');
|
|
|
|
-- Verify
|
|
SELECT * FROM virtual_domains;
|
|
|
|
EXIT;
|
|
```
|
|
|
|
**Save your database password securely!**
|
|
|
|
---
|
|
|
|
## Part 3: Postfix Installation and Configuration
|
|
|
|
### Install Postfix
|
|
|
|
```bash
|
|
pacman -S --noconfirm postfix postfix-mysql
|
|
```
|
|
|
|
### Backup Original Configuration
|
|
|
|
```bash
|
|
cp /etc/postfix/main.cf /etc/postfix/main.cf.orig
|
|
```
|
|
|
|
### Configure Postfix Main Settings
|
|
|
|
Edit `/etc/postfix/main.cf`:
|
|
|
|
```bash
|
|
vim /etc/postfix/main.cf
|
|
```
|
|
|
|
Replace with:
|
|
|
|
```
|
|
# Basic Settings
|
|
myhostname = mail.example.com
|
|
mydomain = example.com
|
|
myorigin = $mydomain
|
|
mydestination = localhost.$mydomain, localhost
|
|
relayhost =
|
|
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
|
|
mailbox_size_limit = 0
|
|
recipient_delimiter = +
|
|
inet_interfaces = all
|
|
inet_protocols = ipv4
|
|
|
|
# Compatibility with Dovecot
|
|
compatibility_level = 3.6
|
|
|
|
# Virtual Mailbox Settings
|
|
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
|
|
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
|
|
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
|
|
|
|
# Virtual transport
|
|
virtual_transport = lmtp:unix:private/dovecot-lmtp
|
|
|
|
# Mailbox Location
|
|
virtual_mailbox_base = /var/mail/vhosts
|
|
virtual_minimum_uid = 100
|
|
virtual_uid_maps = static:5000
|
|
virtual_gid_maps = static:5000
|
|
|
|
# SMTP-AUTH Settings
|
|
smtpd_sasl_type = dovecot
|
|
smtpd_sasl_path = private/auth
|
|
smtpd_sasl_auth_enable = yes
|
|
smtpd_sasl_security_options = noanonymous
|
|
smtpd_sasl_local_domain = $myhostname
|
|
broken_sasl_auth_clients = yes
|
|
|
|
# TLS Settings
|
|
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.example.com/fullchain.pem
|
|
smtpd_tls_key_file=/etc/letsencrypt/live/mail.example.com/privkey.pem
|
|
smtpd_use_tls=yes
|
|
smtpd_tls_auth_only = yes
|
|
smtpd_tls_security_level = may
|
|
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
|
smtpd_tls_ciphers = high
|
|
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
|
smtpd_tls_mandatory_ciphers = high
|
|
|
|
smtp_tls_security_level = may
|
|
smtp_tls_loglevel = 1
|
|
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
|
|
|
|
# SMTP Restrictions
|
|
smtpd_recipient_restrictions =
|
|
permit_sasl_authenticated,
|
|
permit_mynetworks,
|
|
reject_unauth_destination,
|
|
reject_invalid_hostname,
|
|
reject_non_fqdn_hostname,
|
|
reject_non_fqdn_sender,
|
|
reject_non_fqdn_recipient,
|
|
reject_unknown_sender_domain,
|
|
reject_unknown_recipient_domain,
|
|
reject_rbl_client zen.spamhaus.org,
|
|
reject_rbl_client bl.spamcop.net,
|
|
permit
|
|
|
|
smtpd_helo_restrictions =
|
|
permit_mynetworks,
|
|
permit_sasl_authenticated,
|
|
reject_invalid_helo_hostname,
|
|
reject_non_fqdn_helo_hostname,
|
|
reject_unknown_helo_hostname,
|
|
permit
|
|
|
|
smtpd_sender_restrictions =
|
|
permit_mynetworks,
|
|
permit_sasl_authenticated,
|
|
reject_non_fqdn_sender,
|
|
reject_unknown_sender_domain,
|
|
permit
|
|
|
|
# Milter settings (for DKIM)
|
|
milter_default_action = accept
|
|
milter_protocol = 6
|
|
smtpd_milters = inet:127.0.0.1:8891
|
|
non_smtpd_milters = $smtpd_milters
|
|
|
|
# Additional Settings
|
|
disable_vrfy_command = yes
|
|
smtpd_helo_required = yes
|
|
message_size_limit = 52428800
|
|
```
|
|
|
|
### Create MySQL Connection Files
|
|
|
|
**1. Virtual Domains**
|
|
|
|
```bash
|
|
vim /etc/postfix/mysql-virtual-mailbox-domains.cf
|
|
```
|
|
|
|
```
|
|
user = mailuser
|
|
password = your_strong_password_here
|
|
hosts = 127.0.0.1
|
|
dbname = mailserver
|
|
query = SELECT 1 FROM virtual_domains WHERE name='%s'
|
|
```
|
|
|
|
**2. Virtual Mailboxes**
|
|
|
|
```bash
|
|
vim /etc/postfix/mysql-virtual-mailbox-maps.cf
|
|
```
|
|
|
|
```
|
|
user = mailuser
|
|
password = your_strong_password_here
|
|
hosts = 127.0.0.1
|
|
dbname = mailserver
|
|
query = SELECT 1 FROM virtual_users WHERE email='%s'
|
|
```
|
|
|
|
**3. Virtual Aliases**
|
|
|
|
```bash
|
|
vim /etc/postfix/mysql-virtual-alias-maps.cf
|
|
```
|
|
|
|
```
|
|
user = mailuser
|
|
password = your_strong_password_here
|
|
hosts = 127.0.0.1
|
|
dbname = mailserver
|
|
query = SELECT destination FROM virtual_aliases WHERE source='%s'
|
|
```
|
|
|
|
### Secure MySQL Configuration Files
|
|
|
|
```bash
|
|
chmod 640 /etc/postfix/mysql-*.cf
|
|
chown root:postfix /etc/postfix/mysql-*.cf
|
|
```
|
|
|
|
### Configure Postfix Master.cf
|
|
|
|
Edit `/etc/postfix/master.cf`:
|
|
|
|
```bash
|
|
vim /etc/postfix/master.cf
|
|
```
|
|
|
|
Add these lines at the end:
|
|
|
|
```
|
|
submission inet n - n - - smtpd
|
|
-o syslog_name=postfix/submission
|
|
-o smtpd_tls_security_level=encrypt
|
|
-o smtpd_sasl_auth_enable=yes
|
|
-o smtpd_tls_auth_only=yes
|
|
-o smtpd_reject_unlisted_recipient=no
|
|
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
|
|
-o smtpd_helo_restrictions=
|
|
-o smtpd_sender_restrictions=
|
|
-o smtpd_recipient_restrictions=
|
|
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
|
-o milter_macro_daemon_name=ORIGINATING
|
|
|
|
smtps inet n - n - - smtpd
|
|
-o syslog_name=postfix/smtps
|
|
-o smtpd_tls_wrappermode=yes
|
|
-o smtpd_sasl_auth_enable=yes
|
|
-o smtpd_reject_unlisted_recipient=no
|
|
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
|
|
-o smtpd_helo_restrictions=
|
|
-o smtpd_sender_restrictions=
|
|
-o smtpd_recipient_restrictions=
|
|
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
|
-o milter_macro_daemon_name=ORIGINATING
|
|
```
|
|
|
|
### Create Mail Directory Structure
|
|
|
|
```bash
|
|
# Create vmail user and group
|
|
groupadd -g 5000 vmail
|
|
useradd -g vmail -u 5000 vmail -d /var/mail/vhosts -m -s /bin/bash
|
|
|
|
# Create mail directory
|
|
mkdir -p /var/mail/vhosts/example.com
|
|
chown -R vmail:vmail /var/mail/vhosts
|
|
chmod -R 770 /var/mail/vhosts
|
|
```
|
|
|
|
### Test MySQL Connectivity
|
|
|
|
```bash
|
|
postmap -q example.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
|
|
```
|
|
|
|
Should return `1` if working.
|
|
|
|
### Initialize Postfix Aliases
|
|
|
|
```bash
|
|
newaliases
|
|
postmap /etc/postfix/virtual
|
|
```
|
|
|
|
---
|
|
|
|
## Part 4: Dovecot Installation and Configuration
|
|
|
|
### Install Dovecot
|
|
|
|
```bash
|
|
pacman -S --noconfirm dovecot pigeonhole
|
|
```
|
|
|
|
### Main Dovecot Configuration
|
|
|
|
Edit `/etc/dovecot/dovecot.conf`:
|
|
|
|
```bash
|
|
vim /etc/dovecot/dovecot.conf
|
|
```
|
|
|
|
Replace with:
|
|
|
|
```
|
|
protocols = imap lmtp sieve
|
|
listen = *, ::
|
|
dict {
|
|
}
|
|
|
|
!include conf.d/*.conf
|
|
!include_try local.conf
|
|
```
|
|
|
|
### Configure Mail Location
|
|
|
|
Edit `/etc/dovecot/conf.d/10-mail.conf`:
|
|
|
|
```bash
|
|
vim /etc/dovecot/conf.d/10-mail.conf
|
|
```
|
|
|
|
Set these values:
|
|
|
|
```
|
|
mail_location = maildir:/var/mail/vhosts/%d/%n
|
|
mail_privileged_group = vmail
|
|
|
|
namespace inbox {
|
|
inbox = yes
|
|
|
|
mailbox Drafts {
|
|
special_use = \Drafts
|
|
}
|
|
mailbox Junk {
|
|
special_use = \Junk
|
|
}
|
|
mailbox Trash {
|
|
special_use = \Trash
|
|
}
|
|
mailbox Sent {
|
|
special_use = \Sent
|
|
}
|
|
}
|
|
|
|
first_valid_uid = 5000
|
|
last_valid_uid = 5000
|
|
first_valid_gid = 5000
|
|
last_valid_gid = 5000
|
|
```
|
|
|
|
### Configure Authentication
|
|
|
|
Edit `/etc/dovecot/conf.d/10-auth.conf`:
|
|
|
|
```bash
|
|
vim /etc/dovecot/conf.d/10-auth.conf
|
|
```
|
|
|
|
Modify:
|
|
|
|
```
|
|
disable_plaintext_auth = yes
|
|
auth_mechanisms = plain login
|
|
|
|
# Comment out
|
|
#!include auth-system.conf.ext
|
|
|
|
# Uncomment
|
|
!include auth-sql.conf.ext
|
|
```
|
|
|
|
### SQL Authentication Backend
|
|
|
|
Edit `/etc/dovecot/conf.d/auth-sql.conf.ext`:
|
|
|
|
```bash
|
|
vim /etc/dovecot/conf.d/auth-sql.conf.ext
|
|
```
|
|
|
|
```
|
|
passdb {
|
|
driver = sql
|
|
args = /etc/dovecot/dovecot-sql.conf.ext
|
|
}
|
|
|
|
userdb {
|
|
driver = static
|
|
args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
|
|
}
|
|
```
|
|
|
|
### SQL Connection Configuration
|
|
|
|
Create `/etc/dovecot/dovecot-sql.conf.ext`:
|
|
|
|
```bash
|
|
vim /etc/dovecot/dovecot-sql.conf.ext
|
|
```
|
|
|
|
```
|
|
driver = mysql
|
|
connect = host=127.0.0.1 dbname=mailserver user=mailuser password=your_strong_password_here
|
|
|
|
default_pass_scheme = SHA512-CRYPT
|
|
|
|
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
|
|
|
|
user_query = SELECT email as user, 'maildir:/var/mail/vhosts/%d/%n' as mail, 5000 AS uid, 5000 AS gid FROM virtual_users WHERE email='%u';
|
|
|
|
iterate_query = SELECT email AS username FROM virtual_users;
|
|
```
|
|
|
|
Secure it:
|
|
|
|
```bash
|
|
chown root:root /etc/dovecot/dovecot-sql.conf.ext
|
|
chmod 600 /etc/dovecot/dovecot-sql.conf.ext
|
|
```
|
|
|
|
### Master Services Configuration
|
|
|
|
Edit `/etc/dovecot/conf.d/10-master.conf`:
|
|
|
|
```bash
|
|
vim /etc/dovecot/conf.d/10-master.conf
|
|
```
|
|
|
|
Configure services:
|
|
|
|
```
|
|
service imap-login {
|
|
inet_listener imap {
|
|
port = 143
|
|
}
|
|
inet_listener imaps {
|
|
port = 993
|
|
ssl = yes
|
|
}
|
|
}
|
|
|
|
service pop3-login {
|
|
inet_listener pop3 {
|
|
port = 110
|
|
}
|
|
inet_listener pop3s {
|
|
port = 995
|
|
ssl = yes
|
|
}
|
|
}
|
|
|
|
service lmtp {
|
|
unix_listener /var/spool/postfix/private/dovecot-lmtp {
|
|
mode = 0600
|
|
user = postfix
|
|
group = postfix
|
|
}
|
|
}
|
|
|
|
service imap {
|
|
}
|
|
|
|
service pop3 {
|
|
}
|
|
|
|
service auth {
|
|
unix_listener /var/spool/postfix/private/auth {
|
|
mode = 0666
|
|
user = postfix
|
|
group = postfix
|
|
}
|
|
|
|
unix_listener auth-userdb {
|
|
mode = 0600
|
|
user = vmail
|
|
group = vmail
|
|
}
|
|
|
|
user = dovecot
|
|
}
|
|
|
|
service auth-worker {
|
|
user = vmail
|
|
}
|
|
|
|
service dict {
|
|
unix_listener dict {
|
|
}
|
|
}
|
|
```
|
|
|
|
### SSL Configuration
|
|
|
|
Edit `/etc/dovecot/conf.d/10-ssl.conf`:
|
|
|
|
```bash
|
|
vim /etc/dovecot/conf.d/10-ssl.conf
|
|
```
|
|
|
|
```
|
|
ssl = required
|
|
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
|
|
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
|
|
|
|
ssl_min_protocol = TLSv1.2
|
|
ssl_cipher_list = ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
|
|
ssl_prefer_server_ciphers = yes
|
|
```
|
|
|
|
### Sieve Configuration
|
|
|
|
Edit `/etc/dovecot/conf.d/90-sieve.conf`:
|
|
|
|
```bash
|
|
vim /etc/dovecot/conf.d/90-sieve.conf
|
|
```
|
|
|
|
```
|
|
plugin {
|
|
sieve = file:~/sieve;active=~/.dovecot.sieve
|
|
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.execute
|
|
}
|
|
```
|
|
|
|
### Set Permissions
|
|
|
|
```bash
|
|
chown -R vmail:dovecot /etc/dovecot
|
|
chmod -R o-rwx /etc/dovecot
|
|
```
|
|
|
|
---
|
|
|
|
## Part 5: SSL Certificates with Let's Encrypt
|
|
|
|
### Install Certbot
|
|
|
|
```bash
|
|
pacman -S --noconfirm certbot
|
|
```
|
|
|
|
### Obtain Certificate
|
|
|
|
Ensure ports 80 and 443 are accessible:
|
|
|
|
```bash
|
|
certbot certonly --standalone -d mail.example.com
|
|
```
|
|
|
|
Follow prompts and enter your email.
|
|
|
|
### Set Up Auto-Renewal
|
|
|
|
Create systemd timer:
|
|
|
|
```bash
|
|
systemctl enable --now certbot-renew.timer
|
|
```
|
|
|
|
Create renewal hook:
|
|
|
|
```bash
|
|
mkdir -p /etc/letsencrypt/renewal-hooks/post
|
|
vim /etc/letsencrypt/renewal-hooks/post/reload-mail-services.sh
|
|
```
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
systemctl reload postfix
|
|
systemctl reload dovecot
|
|
```
|
|
|
|
Make executable:
|
|
|
|
```bash
|
|
chmod +x /etc/letsencrypt/renewal-hooks/post/reload-mail-services.sh
|
|
```
|
|
|
|
---
|
|
|
|
## Part 6: OpenDKIM Setup
|
|
|
|
### Install OpenDKIM
|
|
|
|
```bash
|
|
pacman -S --noconfirm opendkim
|
|
```
|
|
|
|
### Configure OpenDKIM
|
|
|
|
Edit `/etc/opendkim/opendkim.conf`:
|
|
|
|
```bash
|
|
vim /etc/opendkim/opendkim.conf
|
|
```
|
|
|
|
```
|
|
AutoRestart Yes
|
|
AutoRestartRate 10/1h
|
|
UMask 002
|
|
Syslog yes
|
|
SyslogSuccess Yes
|
|
LogWhy Yes
|
|
|
|
Canonicalization relaxed/simple
|
|
|
|
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
|
|
InternalHosts refile:/etc/opendkim/TrustedHosts
|
|
KeyTable refile:/etc/opendkim/KeyTable
|
|
SigningTable refile:/etc/opendkim/SigningTable
|
|
|
|
Mode sv
|
|
PidFile /run/opendkim/opendkim.pid
|
|
SignatureAlgorithm rsa-sha256
|
|
|
|
UserID opendkim:mail
|
|
|
|
Socket inet:8891@localhost
|
|
```
|
|
|
|
### Create Directory Structure
|
|
|
|
```bash
|
|
mkdir -p /etc/opendkim/keys/example.com
|
|
chown -R opendkim:mail /etc/opendkim
|
|
chmod -R 700 /etc/opendkim/keys
|
|
```
|
|
|
|
# Create Configuration Files
|
|
|
|
**TrustedHosts**:
|
|
|
|
```bash
|
|
vim /etc/opendkim/TrustedHosts
|
|
```
|
|
|
|
```
|
|
127.0.0.1
|
|
localhost
|
|
192.168.1.0/24
|
|
*.example.com
|
|
```
|
|
|
|
**KeyTable**:
|
|
|
|
```bash
|
|
vim /etc/opendkim/KeyTable
|
|
```
|
|
|
|
```
|
|
mail._domainkey.example.com example.com:mail:/etc/opendkim/keys/example.com/mail.private
|
|
```
|
|
|
|
**SigningTable**:
|
|
|
|
```bash
|
|
vim /etc/opendkim/SigningTable
|
|
```
|
|
|
|
```
|
|
*@example.com mail._domainkey.example.com
|
|
```
|
|
|
|
### Generate DKIM Keys
|
|
|
|
```bash
|
|
cd /etc/opendkim/keys/liphlink.xyz
|
|
opendkim-genkey -s mail -d liphlink.xyz
|
|
chown opendkim:mail mail.private
|
|
chmod 600 mail.private
|
|
```
|
|
|
|
### Get Public Key for DNS
|
|
|
|
```bash
|
|
cat /etc/opendkim/keys/liphlink.xyz/mail.txt
|
|
```
|
|
|
|
Save this for your DNS records.
|
|
|
|
### Start OpenDKIM
|
|
|
|
```bash
|
|
systemctl enable --now opendkim
|
|
```
|
|
|
|
---
|
|
|
|
## Part 7: Start and Enable Services
|
|
|
|
### Start All Services
|
|
|
|
```bash
|
|
# Create postfix spool directory for dovecot
|
|
mkdir -p /var/spool/postfix/private
|
|
chown postfix:postfix /var/spool/postfix/private
|
|
|
|
# Start services
|
|
systemctl enable --now postfix
|
|
systemctl enable --now dovecot
|
|
systemctl enable --now opendkim
|
|
|
|
# Check status
|
|
systemctl status postfix
|
|
systemctl status dovecot
|
|
systemctl status opendkim
|
|
```
|
|
|
|
All should show `active (running)`.
|
|
|
|
---
|
|
|
|
## Part 8: Notmuch Integration
|
|
|
|
### Install Notmuch
|
|
|
|
```bash
|
|
pacman -S --noconfirm notmuch
|
|
```
|
|
|
|
### Configure Notmuch for vmail User
|
|
|
|
```bash
|
|
# Switch to vmail user
|
|
su - vmail
|
|
cd /var/mail/vhosts/liphlink.xyz
|
|
|
|
# Create user directory if doesn't exist
|
|
mkdir -p phil
|
|
cd phil
|
|
|
|
# Initialize notmuch
|
|
notmuch setup
|
|
```
|
|
|
|
Prompts:
|
|
|
|
- Your full name: User Name
|
|
- Primary email: user@example.com
|
|
- Maildir location: /var/mail/vhosts/example.com/user
|
|
- Tags for new messages: unread;inbox
|
|
- Tags to exclude: deleted;spam
|
|
|
|
Index existing mail:
|
|
|
|
```bash
|
|
notmuch new
|
|
exit # Exit vmail user
|
|
```
|
|
|
|
### Create Indexing Script
|
|
|
|
```bash
|
|
vim
|
|
```
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
for domain in /var/mail/vhosts/*; do
|
|
if [ -d "$domain" ]; then
|
|
for user in "$domain"/*; do
|
|
if [ -d "$user" ]; then
|
|
cd "$user" || continue
|
|
|
|
if [ ! -d ".notmuch" ]; then
|
|
su -s /bin/bash vmail -c "cd '$user' && notmuch new"
|
|
else
|
|
su -s /bin/bash vmail -c "cd '$user' && notmuch new"
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
done
|
|
```
|
|
|
|
Make executable:
|
|
|
|
```bash
|
|
chmod +x /usr/local/bin/notmuch-index-all.sh
|
|
```
|
|
|
|
### Set Up Automatic Indexing
|
|
|
|
Create systemd service:
|
|
|
|
```bash
|
|
vim /etc/systemd/system/notmuch-index.service
|
|
```
|
|
|
|
```ini
|
|
[Unit]
|
|
Description=Notmuch email indexing
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=/usr/local/bin/notmuch-index-all.sh
|
|
User=root
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
Create timer:
|
|
|
|
```bash
|
|
vim /etc/systemd/system/notmuch-index.timer
|
|
```
|
|
|
|
```ini
|
|
[Unit]
|
|
Description=Run notmuch indexing every 5 minutes
|
|
|
|
[Timer]
|
|
OnBootSec=2min
|
|
OnUnitActiveSec=5min
|
|
|
|
[Install]
|
|
WantedBy=timers.target
|
|
```
|
|
|
|
Enable:
|
|
|
|
```bash
|
|
systemctl daemon-reload
|
|
systemctl enable --now notmuch-index.timer
|
|
```
|
|
|
|
### Configure Dovecot for Real-time Indexing
|
|
|
|
```bash
|
|
vim /usr/local/bin/notmuch-index-single
|
|
```
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
if [ -n "$HOME" ]; then
|
|
cd "$HOME" || exit 0
|
|
/usr/bin/notmuch new > /dev/null 2>&1
|
|
fi
|
|
```
|
|
|
|
Make executable:
|
|
|
|
```bash
|
|
chmod +x /usr/local/bin/notmuch-index-single
|
|
```
|
|
|
|
Create global sieve:
|
|
|
|
```bash
|
|
mkdir -p /var/mail/vhosts/sieve
|
|
vim /var/mail/vhosts/sieve/after.sieve
|
|
```
|
|
|
|
```
|
|
require ["vnd.dovecot.pipe", "copy", "environment"];
|
|
pipe :copy "notmuch-index-single";
|
|
```
|
|
|
|
Compile:
|
|
|
|
```bash
|
|
sievec /var/mail/vhosts/sieve/after.sieve
|
|
chown -R vmail:vmail /var/mail/vhosts/sieve
|
|
```
|
|
|
|
Update Dovecot config:
|
|
|
|
```bash
|
|
vim /etc/dovecot/conf.d/90-sieve.conf
|
|
```
|
|
|
|
Add:
|
|
|
|
```
|
|
plugin {
|
|
sieve = file:~/sieve;active=~/.dovecot.sieve
|
|
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.execute
|
|
sieve_after = /var/mail/vhosts/sieve/after.sieve
|
|
}
|
|
```
|
|
|
|
Restart:
|
|
|
|
```bash
|
|
systemctl restart dovecot
|
|
```
|
|
|
|
---
|
|
|
|
## Part 9: Email Encryption with Dovecot Mail-Crypt
|
|
|
|
### Install Required Packages
|
|
|
|
```bash
|
|
# Already included in dovecot package on Arch
|
|
pacman -S --noconfirm openssl
|
|
```
|
|
|
|
### Generate Master Encryption Keys
|
|
|
|
```bash
|
|
mkdir -p /var/lib/dovecot/mail-crypt
|
|
cd /var/lib/dovecot/mail-crypt
|
|
|
|
# Generate EC keys
|
|
openssl ecparam -name prime256v1 -genkey | openssl pkey -out ecprivkey.pem
|
|
openssl pkey -in ecprivkey.pem -pubout -out ecpubkey.pem
|
|
|
|
# Set permissions
|
|
chown vmail:vmail *.pem
|
|
chmod 400 *.pem
|
|
```
|
|
|
|
### Configure Mail-Crypt Plugin
|
|
|
|
Create `/etc/dovecot/conf.d/90-mail-crypt.conf`:
|
|
|
|
```bash
|
|
vim /etc/dovecot/conf.d/90-mail-crypt.conf
|
|
```
|
|
|
|
```
|
|
mail_plugins = $mail_plugins mail_crypt
|
|
|
|
plugin {
|
|
mail_crypt_global_private_key = </var/lib/dovecot/mail-crypt/ecprivkey.pem
|
|
mail_crypt_global_public_key = </var/lib/dovecot/mail-crypt/ecpubkey.pem
|
|
mail_crypt_save_version = 2
|
|
mail_crypt_curve = secp521r1
|
|
mail_crypt_private_password = %w
|
|
}
|
|
```
|
|
|
|
Update main mail config:
|
|
|
|
```bash
|
|
vim /etc/dovecot/conf.d/10-mail.conf
|
|
```
|
|
|
|
Find `mail_plugins` and add `mail_crypt`:
|
|
|
|
```
|
|
mail_plugins = mail_crypt
|
|
```
|
|
|
|
Restart Dovecot:
|
|
|
|
```bash
|
|
systemctl restart dovecot
|
|
```
|
|
|
|
### Install PGP/GPG Tools
|
|
|
|
```bash
|
|
pacman -S --noconfirm gnupg
|
|
```
|
|
|
|
### PGP Key Management Script
|
|
|
|
```bash
|
|
vim /usr/local/bin/mail-pgp-manager
|
|
```
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
USER_EMAIL="$1"
|
|
ACTION="$2"
|
|
|
|
GNUPG_HOME="/var/mail/vhosts/$(echo $USER_EMAIL | cut -d'@' -f2)/$(echo $USER_EMAIL | cut -d'@' -f1)/.gnupg"
|
|
|
|
case "$ACTION" in
|
|
generate)
|
|
mkdir -p "$GNUPG_HOME"
|
|
chmod 700 "$GNUPG_HOME"
|
|
chown vmail:vmail "$GNUPG_HOME"
|
|
|
|
su - vmail -c "gpg --homedir $GNUPG_HOME --batch --gen-key <<EOF
|
|
Key-Type: RSA
|
|
Key-Length: 4096
|
|
Subkey-Type: RSA
|
|
Subkey-Length: 4096
|
|
Name-Real: $USER_EMAIL
|
|
Name-Email: $USER_EMAIL
|
|
Expire-Date: 0
|
|
%no-protection
|
|
%commit
|
|
EOF"
|
|
;;
|
|
|
|
export-public)
|
|
su - vmail -c "gpg --homedir $GNUPG_HOME --armor --export $USER_EMAIL"
|
|
;;
|
|
|
|
list)
|
|
su - vmail -c "gpg --homedir $GNUPG_HOME --list-keys"
|
|
;;
|
|
|
|
*)
|
|
echo "Usage: $0 <email> <generate|export-public|list>"
|
|
exit 1
|
|
;;
|
|
esac
|
|
```
|
|
|
|
Make executable:
|
|
|
|
```bash
|
|
chmod +x /usr/local/bin/mail-pgp-manager
|
|
```
|
|
|
|
---
|
|
|
|
## Part 10: Creating Email Accounts
|
|
|
|
### Generate Password Hash
|
|
|
|
```bash
|
|
doveadm pw -s SHA512-CRYPT
|
|
```
|
|
|
|
Enter your password. Copy the hash.
|
|
|
|
### Add User to Database
|
|
|
|
```bash
|
|
mysql -u root -p mailserver
|
|
```
|
|
|
|
```sql
|
|
-- Get domain ID
|
|
SELECT id FROM virtual_domains WHERE name='liphlink.xyz';
|
|
|
|
-- Add user (replace hash with your generated hash)
|
|
INSERT INTO virtual_users (domain_id, password, email)
|
|
VALUES (1, '{SHA512-CRYPT}$6$OWM2H5QRTyR5qLky$n1lDTBB7CcHpMNNtXGe4pwC.OH9/hA6Gen3pwWr9R5AoboJuqg9P/gl..WQXuy82cGizNy3WDEzRNWnevqfbx0', 'phil@liphlink.xyz');
|
|
|
|
-- Verify
|
|
SELECT * FROM virtual_users;
|
|
|
|
EXIT;
|
|
```
|
|
|
|
```sql
|
|
-- Get domain ID
|
|
SELECT id FROM virtual_domains WHERE name='liphlink.xyz';
|
|
|
|
-- Add user (replace hash with your generated hash)
|
|
INSERT INTO virtual_users (domain_id, password, email)
|
|
VALUES (1, '{SHA512-CRYPT}$6$5ZnV6ungZJDq00k4$UhNVKgXoJp1AvfTMnqyDFtyECG4/5UNd.ZPlQP9OVdeOpgjssJwP0qaOWCoP0AHjL7/zAsgUR4GIY/YczK2hB1', 'liph@liphlink.xyz');
|
|
|
|
-- Verify
|
|
SELECT * FROM virtual_users;
|
|
|
|
EXIT;
|
|
```
|
|
|
|
### Create Maildir for User
|
|
|
|
```bash
|
|
mkdir -p /var/mail/vhosts/liphlink.xyz/liph/Maildir/{cur,new,tmp}
|
|
chown -R vmail:vmail /var/mail/vhosts/liphlink.xyz/liph
|
|
chmod -R 770 /var/mail/vhosts/liphlink.xyz/liph
|
|
```
|
|
|
|
---
|
|
|
|
## Part 11: Firewall Configuration
|
|
|
|
### Install and Configure UFW
|
|
|
|
```bash
|
|
pacman -S --noconfirm ufw
|
|
|
|
# Allow SSH first!
|
|
ufw allow 22/tcp
|
|
|
|
# Mail server ports
|
|
ufw allow 25/tcp # SMTP
|
|
ufw allow 587/tcp # Submission
|
|
ufw allow 465/tcp # SMTPS
|
|
ufw allow 993/tcp # IMAPS
|
|
ufw allow 143/tcp # IMAP
|
|
ufw allow 80/tcp # HTTP (Let's Encrypt)
|
|
ufw allow 443/tcp # HTTPS
|
|
|
|
# Enable
|
|
ufw enable
|
|
systemctl enable ufw
|
|
```
|
|
|
|
---
|
|
|
|
## Part 12: Security Hardening with Fail2ban
|
|
|
|
### Install Fail2ban
|
|
|
|
```bash
|
|
pacman -S --noconfirm fail2ban
|
|
```
|
|
|
|
### Configure Fail2ban
|
|
|
|
```bash
|
|
vim /etc/fail2ban/jail.local
|
|
```
|
|
|
|
```ini
|
|
[DEFAULT]
|
|
bantime = 3600
|
|
findtime = 600
|
|
maxretry = 5
|
|
|
|
[postfix-sasl]
|
|
enabled = true
|
|
port = smtp,submission,smtps
|
|
logpath = /var/log/mail.log
|
|
filter = postfix-sasl
|
|
|
|
[dovecot]
|
|
enabled = true
|
|
port = pop3,pop3s,imap,imaps,submission,smtps
|
|
logpath = /var/log/mail.log
|
|
filter = dovecot
|
|
```
|
|
|
|
Enable and start:
|
|
|
|
```bash
|
|
systemctl enable --now fail2ban
|
|
```
|
|
|
|
---
|
|
|
|
## Part 13: Testing Everything
|
|
|
|
### Test Postfix
|
|
|
|
```bash
|
|
# Check config
|
|
postfix check
|
|
|
|
# Test MySQL lookups
|
|
postmap -q example.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
|
|
postmap -q user@example.com mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
|
|
```
|
|
|
|
### Test Dovecot Authentication
|
|
|
|
```bash
|
|
doveadm auth test user@example.com
|
|
```
|
|
|
|
### Send Test Email
|
|
|
|
```bash
|
|
# Install mail utility
|
|
pacman -S --noconfirm s-nail
|
|
|
|
# Send test
|
|
echo "Test email" | mail -s "Test" phil@liphlink.xyz
|
|
|
|
# Check logs
|
|
journalctl -u postfix -f
|
|
journalctl -u dovecot -f
|
|
```
|
|
|
|
ALTER USER 'mailuser'@'localhost' IDENTIFIED BY '1ChagemaiL';
|
|
FLUSH PRIVILEGES;
|
|
EXIT;
|
|
|
|
### Test IMAP
|
|
|
|
```bash
|
|
openssl s_client -connect localhost:993 -crlf
|
|
```
|
|
|
|
Then:
|
|
|
|
```
|
|
a LOGIN user@example.com password
|
|
b SELECT INBOX
|
|
c LOGOUT
|
|
```
|
|
|
|
### Test Notmuch
|
|
|
|
```bash
|
|
su - vmail
|
|
cd /var/mail/vhosts/example.com/user
|
|
notmuch search tag:inbox
|
|
notmuch search from:sender@example.com
|
|
exit
|
|
```
|
|
|
|
---
|
|
|
|
## Part 14: Monitoring and Logs
|
|
|
|
### View Logs
|
|
|
|
```bash
|
|
# Postfix logs
|
|
journalctl -u postfix -f
|
|
|
|
# Dovecot logs
|
|
journalctl -u dovecot -f
|
|
|
|
# All mail logs
|
|
journalctl -u postfix -u dovecot -f
|
|
|
|
# OpenDKIM logs
|
|
journalctl -u opendkim -f
|
|
```
|
|
|
|
### Check Service Status
|
|
|
|
```bash
|
|
systemctl status postfix dovecot opendkim mariadb
|
|
```
|
|
|
|
### Check Mail Queue
|
|
|
|
```bash
|
|
postqueue -p
|
|
mailq
|
|
```
|
|
|
|
---
|
|
|
|
## Part 15: Backup Script
|
|
|
|
```bash
|
|
vim /usr/local/bin/mail-backup.sh
|
|
```
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
BACKUP_DIR="/root/mail-backup"
|
|
DATE=$(date +%Y-%m-%d)
|
|
|
|
mkdir -p "$BACKUP_DIR"
|
|
|
|
# Backup configs
|
|
tar -czf "$BACKUP_DIR/postfix-$DATE.tar.gz" /etc/postfix/
|
|
tar -czf "$BACKUP_DIR/dovecot-$DATE.tar.gz" /etc/dovecot/
|
|
tar -czf "$BACKUP_DIR/opendkim-$DATE.tar.gz" /etc/opendkim/
|
|
|
|
# Backup database
|
|
mysqldump -u root -p mailserver > "$BACKUP_DIR/mailserver-$DATE.sql"
|
|
|
|
# Backup mail (optional - can be large)
|
|
# tar -czf "$BACKUP_DIR/vmail-$DATE.tar.gz" /var/mail/vhosts/
|
|
|
|
# Keep only last 7 days
|
|
find "$BACKUP_DIR" -type f -mtime +7 -delete
|
|
|
|
echo "Backup completed: $DATE"
|
|
```
|
|
|
|
Make executable:
|
|
|
|
```bash
|
|
chmod +x /usr/local/bin/mail-backup.sh
|
|
```
|
|
|
|
Schedule with cron or systemd timer.
|
|
|
|
---
|
|
|
|
## Arch Linux Specific Notes
|
|
|
|
### Package Management
|
|
|
|
```bash
|
|
# Update system
|
|
pacman -Syu
|
|
|
|
# Search packages
|
|
pacman -Ss package-name
|
|
|
|
# Install package
|
|
pacman -S package-name
|
|
|
|
# Remove package
|
|
pacman -R package-name
|
|
```
|
|
|
|
### AUR Helper (Optional)
|
|
|
|
For packages not in official repos:
|
|
|
|
```bash
|
|
# Install yay
|
|
pacman -S --noconfirm git base-devel
|
|
git clone https://aur.archlinux.org/yay.git
|
|
cd yay
|
|
makepkg -si
|
|
```
|
|
|
|
### Systemd Journal Size
|
|
|
|
Limit journal size:
|
|
|
|
```bash
|
|
vim /etc/systemd/journald.conf
|
|
```
|
|
|
|
```ini
|
|
[Journal]
|
|
SystemMaxUse=500M
|
|
```
|
|
|
|
Restart:
|
|
|
|
```bash
|
|
systemctl restart systemd-journald
|
|
```
|
|
|
|
---
|
|
|
|
## Quick Reference Commands
|
|
|
|
### User Management
|
|
|
|
```bash
|
|
# Create user with encryption
|
|
doveadm pw -s SHA512-CRYPT
|
|
mysql -u root -p mailserver -e "INSERT INTO virtual_users VALUES (1, 'HASH', 'user@example.com');"
|
|
mail-pgp-manager user@example.com generate
|
|
```
|
|
|
|
### Service Management
|
|
|
|
```bash
|
|
# Restart services
|
|
systemctl restart postfix dovecot opendkim
|
|
|
|
# View logs
|
|
journalctl -u postfix -u dovecot --since "1 hour ago"
|
|
|
|
# Check mail queue
|
|
postqueue -p
|
|
```
|
|
|
|
### Notmuch
|
|
|
|
```bash
|
|
# Manual index
|
|
/usr/local/bin/notmuch-index-all.sh
|
|
|
|
# Check timer
|
|
systemctl status notmuch-index.timer
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Services won't start
|
|
|
|
```bash
|
|
# Check for errors
|
|
systemctl status servicename
|
|
journalctl -xeu servicename
|
|
|
|
# Check configuration
|
|
postfix check
|
|
doveconf -n
|
|
```
|
|
|
|
### Permission issues
|
|
|
|
```bash
|
|
# Fix ownership
|
|
chown -R vmail:vmail /var/mail/vhosts
|
|
chown -R postfix:postfix /var/spool/postfix
|
|
chown -R dovecot:dovecot /etc/dovecot
|
|
|
|
# Fix permissions
|
|
chmod -R 770 /var/mail/vhosts
|
|
chmod 600 /etc/dovecot/dovecot-sql.conf.ext
|
|
```
|
|
|
|
### Database connection fails
|
|
|
|
```bash
|
|
# Test connection
|
|
mysql -u mailuser -p mailserver
|
|
|
|
# Check postfix mysql maps
|
|
postmap -q example.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
|
|
```
|
|
|
|
---
|
|
|
|
## Advantages of Arch Linux for Mail Server
|
|
|
|
✅ **Rolling release**: Always latest stable versions
|
|
✅ **Minimal bloat**: Only what you install
|
|
✅ **Great documentation**: Arch Wiki is excellent
|
|
✅ **Performance**: Optimized packages
|
|
✅ **Control**: Full customization
|
|
✅ **SystemD native**: Modern service management
|
|
✅ **Fast package manager**: Pacman is very fast
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. Configure DNS records (see dns-cloudflare-reference.md)
|
|
2. Test email delivery with mail-tester.com
|
|
3. Set up webmail (Roundcube) if desired
|
|
4. Configure backups
|
|
5. Monitor deliverability
|
|
6. Set up additional security (AppArmor/SELinux)
|
|
|
|
---
|
|
|
|
## Additional Resources
|
|
|
|
- **Arch Wiki Mail Server**: https://wiki.archlinux.org/title/Mail_server
|
|
- **Arch Wiki Postfix**: https://wiki.archlinux.org/title/Postfix
|
|
- **Arch Wiki Dovecot**: https://wiki.archlinux.org/title/Dovecot
|
|
|
|
Your Arch Linux mail server is now complete with encryption, notmuch indexing, and all modern security features! 🚀
|
|
|
|
Enjoy your fully customizable, privacy-respecting email infrastructure on Arch Linux!
|