ISP 邮件服务器指南
![]() 要使用 Alpine Linux 3.x 设置邮件服务器,请参阅 ISP Mail Server 3.x HowTo (讨论) |
全功能邮件服务器
本文档的目标是描述如何设置 postfix、dovecot、clamav、dspam、roundecube 和 postfixadmin 以构建一个全功能“ISP”级别的邮件服务器。
服务器必须提供
- 多个虚拟域
- 每个域的管理员(用于添加/删除虚拟账户)
- 每个域/账户的配额支持
- 通过 IMAP / IMAPS / POP3 / POP3S 下载电子邮件
- 为已验证用户使用 TLS 或 SSL 中继电子邮件 (Submission / SMTPS 协议)
- 标准过滤器(病毒/垃圾邮件/rbl/等)
- Web 邮件客户端
- 增值服务
设置 Lighttpd + PHP
PostfixAdmin 需要 php pgpsql 和 imap 模块,所以我们在此步骤中进行操作。
apk add lighttpd php php-pgsql php-imap
停止并移除 mini_httpd,并将 ACF 移动到 lighttpd;我们将其设置为多域虚拟 Web 服务器(将 host.example.com 替换为实际域名)
rc-service mini_httpd stop apk del mini_httpd mkdir -p /var/www/domains/host.example.com/www ln -s /usr/share/acf/www /var/www/domains/host.example.com/www/acf
编辑 /var/www/domains/host.example.com/www/index.html 以放置一个简单的重定向页面
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>host.example.com Redirector</title> </head> <body> <ul> <li><a href="/acf">ACF</a></li> <li><a href="/postfixadmin">PostfixAdmin</a></li> <li><a href="/roundcube">Roundcube</a></li> </ul> </body>
编辑 /etc/lighttpd/mod_cgi.conf 以通过添加 "" => "" cgi 处理程序来服务 haserl 文件,并将 /acf/cgi-bin 视为 CGI 目录(删除 '^')
$HTTP["url"] =~ "/cgi-bin/" { # disable directory listings dir-listing.activate = "disable" # only allow cgi's in this directory cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", "" => "" ) }
获取 Web 证书并安装它。您有两个选择:1. 如果您想使用自签名证书,可以使用 生成 SSL 证书与 ACF 或 生成 SSL 证书与 ACF 1.9 中找到的说明来生成它。 2. 使用使用 setup-acf 命令创建的证书。
选项 1:如果您创建自己的自签名证书,则可以使用以下命令创建 "server-bundle.pem" 和 "ca-crt.pem" 文件
openssl pkcs12 -nokeys -cacerts -in certificate.pfx -out /etc/lighttpd/ca-crt.pem openssl pkcs12 -nodes -in certificate.pfx -out /etc/lighttpd/server-bundle.pem chown root:root /etc/lighttpd/server-bundle.pem chmod 400 /etc/lighttpd/server-bundle.pem
注意:服务器证书和密钥都在 server-bundle.pem 文件中,因此至关重要的是该文件对用户 "root" 来说是只读的。
选项 2:如果您更喜欢只使用使用 setup-acf 命令创建的默认证书,那么您需要执行以下操作
setup-acf
在上述过程中,如果 mini_httpd 尚未启动,则会启动它,并且将创建证书。完成 setup-acf 步骤后,请执行以下操作以将证书文件移动到 lighttpd 使用的正确位置。
mv /etc/ssl/mini_httpd/server.pem /etc/lighttpd/server-bundle.pem chown root:root /etc/lighttpd/server-bundle.pem chmod 400 /etc/lighttpd/server-bundle.pem
将以下行添加到 /etc/lighttpd/lighttpd.conf 以指向新的文档根目录,并将其设置为监听端口 443(将 host.example.com 替换为实际域名,将 ip_address_of_server 替换为实际 IP 地址)
simple-vhost.server-root = "/var/www/domains/" simple-vhost.default-host = "/host.example.com/" simple-vhost.document-root = "www/" $SERVER["socket"] == "ip_address_of_server:443" { ssl.engine = "enable" ssl.pemfile = "/etc/lighttpd/server-bundle.pem" }
如果您选择了上面的选项 1,则在 ssl.pemfile 行下方添加一行,以便该部分显示如下:
$SERVER["socket"] == "ip_address_of_server:443" { ssl.engine = "enable" ssl.pemfile = "/etc/lighttpd/server-bundle.pem" ssl.ca-file = "/etc/lighttpd/ca-crt.pem" }
确保加载了 simple_vhosts 模块以及 cgi 配置脚本,方法是取消注释 /etc/lighttpd/lighttpd.conf 中的以下行:
server.modules = ( # other modules may be listed "mod_simple_vhost", # other modules may be listed . . . include "mod_cgi.conf" include "mod_fastcgi.conf"
停止并移除 mini_httpd;启动 lighttpd,测试
rc-service mini_httpd stop rc-update del mini_httpd apk del mini_httpd rc-update add lighttpd rc-service lighttpd start
此时,您应该能够看到使用 lighttpd 提供的 ACF(注意:这在 alpine 1.10 上效果良好。在早期版本中会存在问题。)https://host.example.com/acf/
安装 Postgresql
添加并配置 postgresql
apk add acf-postgresql postgresql-client rc-service postgresql setup rc-service postgresql start rc-update add postgresql
此时,任何用户都可以使用 "trust" 机制连接到 sql 服务器。如果您想强制密码身份验证(您可能需要这样做),请编辑 /var/lib/postgresql/8.4/data/pg_hba.conf。
Editme: What should we recommend?
创建 postfix 数据库
psql -U postgres create user postfix with password '******'; create database postfix owner postfix; \c postfix create language plpgsql; \q
(当然,在上面显示 ******* 的位置使用您选择的密码。)
安装 PostfixAdmin
我们将在安装邮件服务器之前安装 postfix 管理 Web 前端。这只是创建一个界面来填充 postfix 和 dovecot 将使用的 SQL 表。
从 Sourceforge 下载 PostfixAdmin。在编写这些说明时,2.3 是当前版本,因此(将 host.example.com 替换为实际域名)
wget https://downloads.sourceforge.net/project/postfixadmin/postfixadmin/postfixadmin-2.3.2/postfixadmin-2.3.2.tar.gz tar zxvf postfixadmin-2.3.2.tar.gz mkdir -p /var/www/domains/host.example.com/www/postfixadmin mv postfixadmin-2.3.2/* /var/www/domains/host.example.com/www/postfixadmin rm -rf postfixadmin*
编辑 /var/www/domains/host.example.com/www/postfixadmin/config.inc.php 并至少修改这些行(将 host.example.com 替换为实际域名)
$CONF['configured'] = true; $CONF['setup_password'] = ""; << Don't change this yet $CONF['database_type'] = 'pgsql'; $CONF['database_host'] = 'localhost'; $CONF['database_user'] = 'postfix'; $CONF['database_password'] = '*****'; << The password you chose above $CONF['database_name'] = 'postfix'; $CONF['database_prefix'] = ""; $CONF['admin_email'] = 'you@some.email.com'; << Your email address $CONF['encrypt'] = 'md5crypt'; $CONF['authlib_default_flavor'] = 'md5raw'; $CONF['dovecotpw'] = "/usr/sbin/dovecotpw"; $CONF['domain_path'] = 'YES'; $CONF['domain_in_mailbox'] = 'NO'; $CONF['aliases'] = '10'; $CONF['mailboxes'] = '10'; $CONF['maxquota'] = '10'; $CONF['quota'] = 'YES'; $CONF['quota_multiplier'] = '1024000'; $CONF['vacation'] = 'NO'; $CONF['vacation_control'] ='NO'; $CONF['vacation_control_admin'] = 'NO'; $CONF['alias_control'] = 'YES'; $CONF['alias_control_admin'] = 'YES'; $CONF['special_alias_control'] = 'YES'; $CONF['fetchmail'] = 'NO'; $CONF['user_footer_link'] = "http://host.example.com/postfixadmin"; $CONF['footer_link'] = 'http://host.example.com/postfixadmin/main.php'; $CONF['create_mailbox_subdirs_prefix']=""; $CONF['used_quotas'] = 'YES'; $CONF['new_quota_table'] = 'YES';
您应该进一步编辑 /var/www/domains/host.example.com/www/postfixadmin/config.inc.php 并将 "change-this-to-your.domain.tld" 的所有实例替换为您的实际邮件域名。这可以使用 busybox sed 完成(将 example.com 替换为您的域名)
sed -i -e 's/change-this-to-your.domain.tld/example.com/g' /var/www/domains/host.example.com/www/postfixadmin/config.inc.php
转到 https://host.example.com/postfixadmin/setup.php
创建密码哈希,将其添加到 config.inc.php 文件
返回 https://host.example.com/postfixadmin/setup.php
创建超级管理员账户。
安装 Postfix
为虚拟邮件传递创建一个用户,并获取其 uid/gid(您将需要 postfix 的数字 uid/gid)
addgroup -S vmail adduser vmail -S -H -D -s /bin/false -G vmail getent passwd vmail
(在以下示例中,我们使用 1006/1006 作为 uid/gid)
创建邮件目录,并将 vmail 分配为所有者
mkdir -p /var/mail/domains chown -R vmail:vmail /var/mail/domains
安装 postfix
apk add acf-postfix postfix-pgsql
编辑 /etc/postfix/main.cf 文件。这是一个示例(不要忘记替换 uid/gid)
myhostname=host.example.com mydomain=example.com mydestination = localhost.$mydomain, localhost mynetworks_style = subnet mynetworks = 127.0.0.0/8 virtual_mailbox_domains = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_domains_maps.cf virtual_alias_maps = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_maps.cf, proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_maps.cf, proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_catchall_maps.cf virtual_mailbox_maps = proxy:pgsql:/etc/postfix/sql/pgsql_virtual_mailbox_maps.cf, proxy:pgsql:/etc/postfix/sql/pgsql_virtual_alias_domain_mailbox_maps.cf virtual_mailbox_base = /var/mail/domains/ virtual_gid_maps = static:1006 virtual_uid_maps = static:1006 virtual_minimum_uid = 100 virtual_transport = virtual # This next command means you must create a virtual # domain for the host itself - ALL mail goes through # The virtual transport mailbox_transport = virtual local_transport = virtual local_transport_maps = $virtual_mailbox_maps smtpd_helo_required = yes disable_vrfy_command = yes message_size_limit = 10240000 queue_minfree = 51200000 smtpd_sender_restrictions = permit_mynetworks, reject_non_fqdn_sender, reject_unknown_sender_domain smtpd_recipient_restrictions = reject_non_fqdn_recipient, reject_unknown_recipient_domain, permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, reject_rbl_client dnsbl.sorbs.net, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net smtpd_data_restrictions = reject_unauth_pipelining # we will use this later - This prevents cleartext authentication # for relaying smtpd_tls_auth_only = yes
现在我们需要创建 *大量* 文件,以便 postfix 可以从 sql 中获取传递信息。这是一个用于创建脚本的 shell 脚本。将 PGPW 更改为 postfix SQL 数据库的 postfix 用户的密码。
cd /etc/postfix mkdir sql PGPW="ChangeMe" cat - <<EOF >sql/pgsql_virtual_alias_domain_catchall_maps.cf user=postfix password = $PGPW hosts = localhost dbname = postfix query = Select goto From alias,alias_domain where alias_domain.alias_domain = '%d' and alias.address = '@' || alias_domain.target_domain and alias.active = true and alias_domain.active= true EOF cat - <<EOF >sql/pgsql_virtual_alias_domain_mailbox_maps.cf user=postfix password = $PGPW hosts = localhost dbname = postfix query = Select maildir from mailbox,alias_domain where alias_domain.alias_domain = '%d' and mailbox.username = '%u' || '@' || alias_domain.target_domain and mailbox.active = true and alias_domain.active EOF cat - <<EOF >sql/pgsql_virtual_alias_domain_maps.cf user=postfix password = $PGPW hosts = localhost dbname = postfix query = select goto from alias,alias_domain where alias_domain.alias_domain='%d' and alias.address = '%u' || '@' || alias_domain.target_domain and alias.active= true and alias_domain.active= true EOF cat - <<EOF >sql/pgsql_virtual_alias_maps.cf user=postfix password = $PGPW hosts = localhost dbname = postfix query = Select goto From alias Where address='%s' and active ='1' EOF cat - <<EOF >sql/pgsql_virtual_domains_maps.cf user=postfix password = $PGPW hosts = localhost dbname = postfix query = Select domain from domain where domain='%s' and active='1' EOF cat - <<EOF >sql/pgsql_virtual_mailbox_maps.cf user=postfix password = $PGPW hosts = localhost dbname = postfix query = Select maildir from mailbox where username='%s' and active=true EOF chown -R postfix:postfix sql chmod 640 sql/*
此时,您应该能够启动 postfix
newaliases # so postfix is happy... rc-service postfix start rc-update add postfix
在 PostfixAdmin 中创建域并测试
转到 http://host.example.com/postfixadmin/
使用超级管理员账户登录,为本地框创建一个域(例如 example.com),并创建一个用户邮箱(例如 root)。
从机器发送测试消息
sendmail -t root@example.com subject: test . ^d
在 /var/log/mail.log (或 /var/log/messages,如果您仍在运行 busybox syslogd)中,您应该看到消息已排队。该消息应位于 /var/mail/domains/example.com/root/new 中。
安装 Dovecot
Dovecot 是用于检索邮件的 POP3/IMAP 服务器。
和以前一样,我们安装 dovecot
apk add acf-dovecot dovecot-pgsql
备份默认配置
mv /etc/dovecot/dovecot.conf
使用以下内容创建一个新的 /etc/dovecot/dovecot.conf
auth_mechanisms = plain login auth_username_format = %Lu auth_verbose = yes disable_plaintext_auth = no info_log_path = /var/log/dovecot-info.log log_path = /var/log/dovecot.log mail_location = maildir:/var/mail/domains/%d/%n passdb { args = /etc/dovecot/dovecot-sql.conf driver = sql } plugin { autocreate = Trash autocreate2 = Spam autocreate3 = Sent autosubscribe = Trash autosubscribe2 = Spam autosubscribe3 = Sent } protocols = pop3 imap # uncomment if you want disable imap on port 143 to enforce imaps #service imap-login { # inet_listener imap { # port = 0 # } #} ssl_cert = </etc/lighttpd/server-bundle.pem ssl_key = </etc/lighttpd/server-bundle.pem userdb { args = uid=1006 gid=1006 home=/var/mail/domains/%d/%n first_valid_uid=100 driver = static } protocol imap { mail_plugins = autocreate }
请务必将 uid 和 gid 替换为 vmail 用户的适当值。
我们需要一个用于 SSL/TLS 身份验证的证书,因此在上面的示例中,我们使用了 lighttpd 证书。这样,当证书续订/替换时,Dovecot 也将可以访问新证书。
创建 /etc/dovecot/dovecot-sql.conf 文件
driver = pgsql connect = host=localhost dbname=postfix user=postfix password=******** password_query = select username,password from mailbox where local_part = '%n' and domain = '%d' default_pass_scheme = MD5-CRYPT
再次,将上面的密码更改为您的 postfix 用户密码,并保护该文件免受窥探。
chown root:root /etc/dovecot/dovecot-sql.conf chmod 600 /etc/dovecot/dovecot-sql.conf
启动 dovecot
rc-service dovecot start rc-update add dovecot
测试
确保您的防火墙允许端口 25(SMTP)、110 (POP3)、995 (POP3S)、143(IMAP)、993(IMAPS) 或您支持的任何子集进入。
此时,您应该能够:
* Create a new domain and add users with PostfixAdmin * Send mail to those users via SMTP to port 25 * Retrieve mail using the user's full email and password (e.g. username: user@example.com password: ChangeMe)
增值功能
如果您按照上面的指南进行操作,那么您现在就拥有了一个功能齐全的邮件服务器,其中包含许多互连的部件。以下功能假设服务器已按照上述说明运行。您应该能够添加以下任何或所有功能,以进一步增强邮件服务。
病毒扫描
此过程使用 clamav 和 postfix content_filter 机制来扫描入站和出站电子邮件中的病毒。受感染的电子邮件将被丢弃。干净的电子邮件将标记为 "scanned by clamav" 标头。
- 安装 clamav 和 clamsmtp
apk add acf-clamav clamsmtp
- 如果需要,编辑 /etc/clamav/clamd.conf 文件(在大多数情况下不是必需的)
- 编辑 /etc/clamsmtpd.conf 并验证以下行
OutAddress: 10026 Listen: 127.0.0.1:10025 Header: X-Virus-Scanned: ClamAV using ClamSMTP Action: drop User: clamav
- 启动守护程序
rc-update add clamd rc-update add clamsmtpd rc-service clamd start rc-service clamsmtpd start
- 验证 clamsmtp 正在监听端口 10025
cmd|netstat -anp | grep clamsmtp
- 按照 clamsmtp 说明进行操作
- 编辑 /etc/postfix/main.cf 并添加
content_filter = scan:[127.0.0.1]:10025
- 编辑 /etc/postfix/master.cf 并添加
# AV scan filter (used by content_filter) scan unix - - n - 16 smtp -o smtp_send_xforward_command=yes -o smtp_enforce_tls=no # For injecting mail back into postfix from the filter 127.0.0.1:10026 inet n - n - 16 smtpd -o content_filter= -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks -o smtpd_helo_restrictions= -o smtpd_client_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks_style=host -o smtpd_authorized_xforward_hosts=127.0.0.0/8
- postfix reload
- 发送电子邮件到本地虚拟域 - 它应该具有 X-Virus-Scanned: ClamAV using ClamSMTP 标头。
为已验证用户中继
如上所述配置,邮件服务器接受来自 Internet 的电子邮件,但它不中继电子邮件。如果它是受保护网络的边界交换器,那么您可以将受保护网络添加到 /etc/postfix/main.cf 中的 mynetworks 配置行。
此配置更改允许远程用户对邮件服务器进行身份验证并通过它进行中继。中继规则是:
- 只有经过身份验证的用户才能中继
- 身份验证凭据必须使用 TLS 或 SSL 加密
- 允许 Submission 和 SMTPS 端口进行中继(许多消费者网络默认阻止端口 25 - SMTP)
该过程使用 dovecot 身份验证机制(与 IMAPS 一起使用)在允许用户通过 postfix 中继之前对用户进行身份验证。
- 编辑 /etc/dovecot/dovecot.conf 并添加以下内容
service auth { # this is for postfix SASL (authenticated users can relay through us) unix_listener /var/spool/postfix/private/dovecot-auth.sock { group = postfix mode = 0660 user = postfix } }
- 重启 dovecot
rc-service dovecot restart
- 编辑 /etc/postfix/main.cf 并添加
# TLS Stuff -- since we allow SASL with tls *only*, we have to set up TLS first smtpd_tls_cert_file = /etc/lighttpd/server-bundle.pem smtpd_tls_key_file = /etc/lighttpd/server-bundle.pem smtpd_tls_CAfile = /etc/lighttpd/ca-crt.pem # If tls_security_level is set to "encrypt", then SMTP rejects # unencrypted email (e.g. normal mail) which is bad. # By setting it to "may" you get TLS encrypted mail from google, slashdot, and other # interesting places. Check your logs to see who smtpd_tls_security_level = may # Log info about the negotiated encryption levels smtpd_tls_received_header = yes smtpd_tls_loglevel = 1 # SASL - this allows senders to authenticiate themselves # This along with "permit_sasl_authenticated" in smtpd_recipient_restrictions allows relaying smtpd_sasl_type = dovecot smtpd_sasl_path = private/dovecot-auth.sock smtpd_sasl_auth_enable = yes smtpd_sasl_authenticated_header = yes broken_sasl_auth_clients = yes smtpd_tls_auth_only = yes
- 编辑 /etc/postfix/master.cf 并启用 submission 和 smtps 传输。它们可能已经位于您的 master.cf 文件顶部,只是被注释掉了
submission inet n - n - - smtpd -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING smtps inet n - n - - smtpd -o smtpd_tls_security_level=encrypt -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING
- 验证 submission 和 smtps 在 /etc/services 中定义
grep "submission\|ssmtp" /etc/services submission 587/tcp # mail message submission submission 587/udp smtps 465/tcp ssmtp # smtp protocol over TLS/SSL smtps 465/udp ssmtp
- 重启 postfix
postfix reload
此时,您应该能够设置邮件客户端以通过 TLS(端口 587)或 SSL(端口 465)通过服务器中继。请注意,由于底层链接已加密,因此使用 "plain" 身份验证。例如,在 Thunderbird 中,取消选中 "安全身份验证",然后为连接安全性选择 STARTTLS(或 TLS)。
邮箱配额
在默认配置中,PostfixAdmin 知道配额,但它们未强制执行。Web 上的文档提到了 vda 补丁到 postfix 以强制执行配额。唯一不好的是...它是一个补丁。Postfix 和 Dovecot 都是保守系统,因此如果补丁不在上游源中,我们将假定有充分的理由。有一种无需补丁即可使用配额的方法 - 它涉及使用 dovecot 的 deliver lda 进行本地传递。
注意:截至 2010 年 1 月,文档令人困惑,其中引用了多个版本的 dovecot、PostfixAdmin 和 Mysql。这些说明适用于:
- Postgresql 8.4.2
- PostfixAdmin 2.3
- Dovecot 1.2.13
- Postfix 2.6.5
据推测,更高版本的工作方式相同,但如果不是,请更新上面的文档和版本。
- 更新 /etc/dovecot/dovecot.conf(旧行显示为注释掉)
# old postfix # userdb static { # args = uid=1006 gid=1006 home=/var/mail/domains/%d/%n # } # new quota support: userdb prefetch { } userdb sql { args = /etc/dovecot/dovecot-sql.conf } socket listen { client { path = /var/spool/postfix/private/dovecot-auth.sock mode = 0660 user = postfix group = postfix } # These lines below are for the deliver lda master { path = /var/run/dovecot/auth-master mode = 0660 user = vmail group = vmail } } } #user = root #} protocol imap { mail_plugins = quota imap_quota } protocol pop3 { mail_plugins = quota } dict { quotadict = pgsql:/etc/dovecot/dovecot-dict-quota.conf } plugin { quota = dict:user::proxy::quotadict } protocol lda { postmaster_address = postmaster@host.example.com mail_plugins = quota auth_socket_path = /var/run/dovecot/auth-master sendmail_path = /usr/sbin/sendmail }
您应该已经有一个:socket-> listen-> client部分,但上面列出了它在与以下关系中的位置:socket -> listen -> master部分
- 编辑/etc/dovecot/dovecot-sql.conf并将用户和密码查询替换为以下内容(您可能还没有 user_query - 添加它)
password_query = select username as user, password, 1006 as userdb_uid, 1006 as userdb_gid, '*:bytes=' || quota as userdb_quota_rule from mailbox where local_part = '%n' and domain = '%d' user_query = select '/var/mail/domains/' || maildir as home, 1006 as uid, 1006 as gid, '*:bytes=' || quota as quota_rule from mailbox where local_part = '%n' and domain ='%d'
- 创建/etc/dovecot/dovecot-dict-quota.conf
connect = host=localhost dbname=postfix user=postfix password=******** map { pattern = priv/quota/storage table = quota2 username_field =username value_field = bytes } map { pattern= priv/quota/messages table = quota2 username_field = username value_field = messages }
再次,将上面的密码更改为您的 postfix 用户密码,并保护该文件免受窥探。
chown root:root /etc/dovecot/dovecot-dict-quota.conf chmod 600 /etc/dovecot/dovecot-dict-quota.conf
旁注:Dovecot 配额文档 提到了 pgsql 需要触发器。这是在 PostfixAdmin 安装中创建的,这就是为什么您在创建数据库时实例化 pgsql 语言的原因。如果不是,您将需要创建触发器,以引用 quota2 表,而不是 dovecot 文档中提到的 quota 表。
- 为 dovecot lda 创建一个新的传输。将以下内容添加到 /etc/postfix/master.cf:
# The dovecot deliver lda dovecot unix - n n - - pipe flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${user}@${nexthop}
- 编辑 /etc/postfix/main.cf。替换:
virtual_transport = virtual
替换为:
virtual_transport = dovecot dovecot_destination_recipient_limit = 1
更改 /var/log/dovecot* 日志文件的权限,以便 vmail 用户可以写入它们。
chown vmail:vmail /var/log/dovecot*
重启 Postfix 和 Dovecot
rc-service postfix restart rc-service dovecot restart
TODO 这将导致超出配额的电子邮件被退回。这可能是反向散射的来源。我们需要一种在 RBL 检查后但在消息被队列接受之前检查配额限制的方法。
WebMail (RoundCube)
RoundCube 是一个 "ajax /Web2.0" Web 邮件客户端。这些说明适用于 Alpine Linux 1.10 存储库。
- 验证您在 /etc/postfix/main.cf 中至少有以下内容。除非您遵循了上面的 "为已验证用户中继" 部分,否则将 smtpd_tls_auth_only = no 设置为 no,否则将其设置为 yes
# SASL - this allows senders to authenticiate themselves # This along with "permit_sasl_authenticated" in smtpd_recipient_restrictions allows relaying smtpd_sasl_type = dovecot smtpd_sasl_path = private/dovecot-auth.sock smtpd_sasl_auth_enable = yes smtpd_sasl_authenticated_header = yes # Set the next line to no if TLS auth is not configured smtpd_tls_auth_only = no
- 确保您在 /etc/dovecot/dovecot.conf 的 auth default 节中包含此部分。
# this is for postfix SASL (authenticated users can relay through us) socket listen { client { path = /var/spool/postfix/private/dovecot-auth.sock mode = 0660 user = postfix group = postfix } } }
- 重启相关服务
rc-service postfix restart rc-service dovecot restart
- 添加软件包和相关的 php 模块
apk add roundcubemail php-xml php-openssl php-mcrypt php-gd php-iconv php-dom php-json php-intl
- 将 roundcube 应用程序链接回 docroot
ln -s /usr/share/webapps/roundcube /var/www/domains/host.example.com/www/roundcube
- 按照 /usr/share/webapps/roundcube/INSTALL 中的说明进行操作
cd /usr/share/webapps/roundcube chown -R lighttpd:lighttpd temp logs su postgres createuser roundcube Shall the new role be a superuser? (y/n) n Shall the new role be allowed to create databases? (y/n) n Shall the new role be allowed to create more new roles? (y/n) y createdb -O roundcube -E UNICODE -T template0 roundcubemail psql roundcubemail roundcubemail=# ALTER USER roundcube WITH PASSWORD 'the_new_password'; roundcubemail=# \c - roundcube roundcubemail=> \i /usr/share/webapps/roundcube/SQL/postgres.initial.sql [Question to experts: Is this error message normal at this point? "could not save history to file "/var/lib/postgresql/.psql_history": Permission denied"] roundcubemail=> \q exit
- 编辑 /etc/php/php.ini 并将 date.timezone 设置为您的本地时区或 UTC
- 重启 lighttpd 以验证是否使用了新的 php 库
rc-service lighttpd restart
- 将您的浏览器指向 https://host.example.com/roundcube/installer
- 开始安装
对于安装步骤中的特定配置参数:
属性 | 设置 |
---|---|
enable_spellcheck | 禁用 |
identities_level | 一个身份,可以编辑所有参数,但不能编辑电子邮件地址 |
log driver | syslog |
sylog_id | roundcube |
syslog_facility | 邮件子系统 |
db_dnsw | pgsql 属性,如上所述 |
imap_host | 127.0.0.1 |
auto_create_user | 已启用 |
smtp_server | 127.0.0.1 |
smtp_port | 25 |
smtp_user/smtp_pass | 启用 使用当前 IMAP 用户名和密码进行 SMTP 身份验证 |
smtp_log | 启用(可选,但提供额外的日志记录) |
其他项目可以保留默认设置,也可以根据需要进行调整。
- 按照安装步骤 2 中的说明将文件复制到服务器
- 您现在应该能够通过 https://host.example.com/roundcube 访问 roundcube
在它工作后,INSTALL 文件建议删除安装目录。如果您想稍后保留安装程序,您可以简单地更改所有权和权限。因此,请执行以下操作之一
cd /usr/share/webapps/roundcube rm -rf LICENSE UPGRADING INSTALL README CHANGELOG SQL installer
或
cd /usr/share/webapps/roundcube chown -R root:root LICENSE UPGRADING INSTALL README CHANGELOG SQL installer chmod -R 600 LICENSE UPGRADING INSTALL README CHANGELOG SQL chmod 700 SQL installer
启用插件
RoundCube 有各种有用的插件,可以在 /usr/share/webapps/roundcube/plugins 目录中找到。例如,您可能想要启用 password 插件,以允许用户直接从 RoundCube 使用添加到用户设置的额外密码选项卡来更改其密码。
- 授予 roundcube 数据库角色有限的权限
psql -U postgres postfix postfix=# GRANT UPDATE (password,modified) ON mailbox TO roundcube; postfix=# GRANT SELECT (username) ON mailbox TO roundcube; postfix=# GRANT INSERT ON log TO roundcube; postfix=# \q
- 在 /usr/share/webapps/roundcube/plugins/password/config.inc.php 中设置 password 插件参数
mv /usr/share/webapps/roundcube/plugins/password/config.inc.php.dist /usr/share/webapps/roundcube/plugins/password/config.inc.php vi /usr/share/webapps/roundcube/plugins/password/config.inc.php
$rcmail_config['password_minimum_length'] = 7; $rcmail_config['password_require_nonalpha'] = true; ... $rcmail_config['password_db_dsn'] = 'pgsql://roundcube:<roundcube_password>@localhost/postfix'; ... $rcmail_config['password_query'] = "UPDATE mailbox set password = %c, modified = NOW() where username = %u; INSERT INTO log (timestamp,username,domain,action,data) VALUES (NOW(),%u || ' (' || %h || ')',%d,'edit_password',%u)";
- 启用 password 插件
vi /usr/share/webapps/roundcube/config/main.inc.php
... $rcmail_config['plugins'] = array('password');
- 为 RoundCube 启用 create_default_folders
vi /usr/share/webapps/roundcube/config/main.inc.php
... $rcmail_config['create_default_folders'] = TRUE; ...
基于 OpenLDAP 的地址簿
此 OpenLDAP 配置使用 SQL 后端,该后端将存储在 PostgreSQL 中的信息表示为 LDAP 子树,用于地址簿功能,用于电子邮件查找、用户身份验证,甚至站点之间的复制帐户信息。此过程使用一些元信息将 LDAP 查询转换为 SQL 查询,保持关系模式不变,这允许 SQL 和 LDAP 应用程序在没有复制的情况下互操作,并根据需要交换数据。SQL 后端使用 UnixODBC 连接到 PostgresSQL。
- 安装 OpenLDAP 和 ODBC
apk add openldap libldap openldap-back-sql php-ldap unixodbc psqlodbc ca-certificates
注意:psqlodbc 软件包当前不可用
- 更新 "postfix" 数据库(它将向 mailbox 和 domain 表添加 "id" 列,还将创建表和视图以表示 LDAP 元信息)
注意:这些说明适用于示例域 example.com。因此,请确保根据您的域名部分替换了 "example" 和 "com" 的所有条目。
将以下内容放入名为 script 的新文件中
ALTER TABLE domain ADD COLUMN id SERIAL; ALTER TABLE mailbox ADD COLUMN id SERIAL; CREATE TABLE ldap_entry_objclasses ( entry_id integer NOT NULL, oc_name character varying(64) ); CREATE TABLE ldap_oc_mappings ( name character varying(64) NOT NULL, keytbl character varying(64) NOT NULL, keycol character varying(64) NOT NULL, create_proc character varying(255), delete_proc character varying(255), expect_return integer NOT NULL ); ALTER TABLE ldap_oc_mappings ADD COLUMN id SERIAL; ALTER TABLE ldap_oc_mappings ADD PRIMARY KEY (id); CREATE TABLE ldap_attr_mappings ( oc_map_id integer NOT NULL REFERENCES ldap_oc_mappings(id), name character varying(255) NOT NULL, sel_expr character varying(255) NOT NULL, sel_expr_u character varying(255), from_tbls character varying(255) NOT NULL, join_where character varying(255), add_proc character varying(255), delete_proc character varying(255), param_order integer NOT NULL, expect_return integer NOT NULL ); ALTER TABLE ldap_attr_mappings ADD COLUMN id SERIAL; ALTER TABLE ldap_attr_mappings ADD PRIMARY KEY (id); CREATE VIEW ldap_dcs AS ((SELECT (domain.id + 100000) AS id, ('dc='::text || replace((domain.domain)::text, '.'::text, ',dc='::text)) AS dn, 1 AS oc_map_id, 100000 AS parent, 0 AS keyval, domain.domain FROM domain WHERE domain.domain <> 'ALL') UNION (SELECT 100000 AS id, ('dc=' || regexp_replace((domain.domain)::text, '.*\\.', ''::text)) AS dn, 1 AS oc_map_id, 0 AS parent, 0 AS keyval, (regexp_replace((domain.domain)::text, '.*\\.', ''::text)) AS domain FROM domain WHERE domain.domain <> 'ALL' LIMIT 1)); CREATE VIEW ldap_entries AS SELECT mailbox.id, ((('cn='::text || initcap(replace(split_part((mailbox.username)::text, '@'::text, 1), '.'::text, ' '::text))) || ',dc='::text) || replace(regexp_replace((mailbox.username)::text, '.*@', ''::text), '.'::text, ',dc='::text)) AS dn, 1 AS oc_map_id, (SELECT ldap_dcs.id FROM ldap_dcs WHERE ((ldap_dcs.domain)::text = (mailbox.domain)::text)) AS parent, mailbox.id AS keyval FROM mailbox UNION SELECT ldap_dcs.id, ldap_dcs.dn, ldap_dcs.oc_map_id, ldap_dcs.parent, ldap_dcs.keyval FROM ldap_dcs;
向专家提问:在此脚本中出现 "WARNING: nonstandard use of \\ in a string literal" 是否正常?
最后,使用以下命令执行文件中的命令:
cat script | psql -U postfix postfix rm script
- 按照以下示例填写 LDAP 表(确保使用 TAB 分隔值)
将以下内容放入名为 script 的新文件中
COPY ldap_oc_mappings (id, name, keytbl, keycol, create_proc, delete_proc, expect_return) FROM stdin; 1 exampleBox mailbox id \N \N 1 \. COPY ldap_attr_mappings (id, oc_map_id, name, sel_expr, sel_expr_u, from_tbls, join_where, add_proc, delete_proc, param_order, expect_return) FROM stdin; 1 1 displayName mailbox.name \N mailbox \N \N \N 3 0 2 1 mail mailbox.username \N mailbox \N \N \N 3 0 3 1 cn mailbox.name \N mailbox \N \N \N 3 0 4 1 userPassword '{CRYPT}'||mailbox.password \N mailbox \N \N \N 3 0 \.
最后,使用以下命令执行文件中的命令:
cat script | psql -U postfix postfix rm script
- 检查 "ldap_dcs" 视图看起来像这样
echo 'select * from ldap_dcs' | psql -U postgres postfix
id | dn | oc_map_id | parent | keyval | domain --------+-----------------------------+-----------+--------+--------+-------------------- 100000 | dc=com | 1 | 0 | 0 | com 100001 | dc=example,dc=com | 1 | 100000 | 0 | example.com
- 检查 "ldap_entries" 视图看起来像这样
echo 'select * from ldap_entries' | psql -U postgres postfix
id | dn | oc_map_id | parent | keyval --------+-------------------------------------------------------+-----------+--------+-------- 1 | cn=address1,dc=example,dc=com | 1 | 100001 | 1 ... 123 | cn=address123,dc=example,dc=com | 1 | 100001 | 1 100000 | dc=com | 1 | 0 | 0 100001 | dc=example,dc=com | 1 | 100000 | 0
- 配置 ODBC 参数
编辑 /etc/odbc.ini
[PostgreSQL] Description = Connection to Postgres Driver = PostgreSQL Trace = Yes TraceFile = sql.log Database = postfix Servername = 127.0.0.1 UserName = Password = Port = 5432 Protocol = 6.4 ReadOnly = No RowVersining = No ShowSystemTables = No ShowOidColumn = No FakeOidIndex = No ConnSettings =
编辑 /etc/odbcinst.ini
[PostgreSQL] Description = PostgreSQL driver for Linux Driver = /usr/lib/psqlodbcw.so Setup = /usr/lib/libodbcpsqlS.so FileUsage = 1
- 测试 ODBC 连接
echo "select * from domain;" | isql PostgreSQL postgres
- 为 LDAP 服务器提供证书权限
chown ldap /etc/lighttpd/server-bundle.pem
- 编辑 LDAP 架构
编辑 /etc/openldap/schema/example.com.schema
attributetype ( 0.9.2342.19200300.100.1.3 NAME ( 'mail' 'rfc822Mailbox' ) DESC 'RFC1274: RFC822 Mailbox' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} ) attributetype ( 2.16.840.1.113730.3.1.241 NAME 'displayName' DESC 'RFC2798: preferred name to be used when displaying entries' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) objectclass ( 2.16.840.1.113730.3.2.2 NAME 'exampleBox' DESC 'example.com mailbox' MUST ( displayName $ mail $ userPassword ) ) # RFC 1274 + RFC 2247 attributetype ( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domainComponent' ) DESC 'RFC1274/2247: domain component' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.5.4.46 NAME 'dnQualifier' DESC 'RFC2256: DN qualifier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
- 配置 LDAP 服务器
编辑 /etc/openldap/slapd.conf
include /etc/openldap/schema/example.com.schema pidfile /var/run/openldap/slapd.pid argsfile /var/run/openldap/slapd.args # Uncomment next five TLS... lines if you want to use LDAPs (secured). Probably you don't want it... #TLSCipherSuite HIGH #TLSCACertificateFile /etc/lighttpd/ca-crt.pem #TLSCertificateFile /etc/lighttpd/server-bundle.pem #TLSCertificateKeyFile /etc/lighttpd/server-bundle.pem #TLSVerifyClient never # This is needed for proper representation of MD5-CRYPT format stored in database # see more details in https://strugglers.net/~andy/blog/2010/01/23/openldap-and-md5crypt/ password-hash {CRYPT} password-crypt-salt-format "$1$%.8s" loglevel stats moduleload /usr/lib/openldap/back_sql.so sizelimit 3000 database sql dbname PostgreSQL dbuser postfix dbpasswd ***** suffix "dc=example,dc=com" upper_func "upper" strcast_func "text" concat_pattern "?||?" has_ldapinfo_dn_ru no lastmod off access to attrs=userPassword by * auth access to * by peername.ip=127.0.0.1 read # by peername.ip=<IP>%<netmask> read # by peername.ip=<IP> read by users read
- 设置 slapd.conf 的权限
chown ldap:ldap /etc/openldap/slapd.conf
- 配置启动参数以确保 LDAP 服务器在 PostgreSQL 之后启动,并使用纯文本在 localhost 上监听,并使用 SSL 在公共 IP 上监听。如果您在 slapd.conf 中取消注释了 TLS 行,请使用此字符串:OPTS="-h 'ldaps:// ldap://'"
编辑 /etc/conf.d/slapd
rc_need="postgresql" OPTS="-h 'ldap://'"
- 启动 LDAP 服务器
rc-update add slapd default rc-service slapd start
- 配置 LDAP 客户端实用程序。如果您在 slapd.conf 中取消注释了 TLS 行,请将 ldap 替换为 ldaps
编辑 /etc/openldap/ldap.conf
BASE dc=example,dc=com URI ldap://host.example.com # Uncomment next three TLS... lines if you want to use LDAPs (secured). Probably you don't want it... #TLS_CACERT /etc/lighttpd/ca-crt.pem #TLS_CERT /etc/lighttpd/server-bundle.pem #TLS_KEY /etc/lighttpd/server-bundle.pem
- 测试 LDAP 服务器
ldapsearch -z 3 ldapsearch -z 3 -x -W -D cn=admin,dc=example,dc=com ldapsearch -z 3 -x -W -D cn=address1,dc=example,dc=com
- 配置 RoundCube Webmail 以进行电子邮件查找
为了启用 php-ldap 支持,您需要重启 lighttpd 服务器。
rc-service lighttpd restart
编辑 /usr/share/webapps/roundcube/config/main.inc.php
$rcmail_config['ldap_debug'] = false; ... $rcmail_config['address_book_type'] = 'sql'; $rcmail_config['ldap_public']['example.com'] = array( 'name' => 'example.com', 'hosts' => array('127.0.0.1'), 'port' => 389, 'use_tls' => false, 'user_specific' => false, 'base_dn' => 'dc=example,dc=com', 'bind_dn' => '', 'bind_pass' => '', 'writable' => false, 'LDAP_Object_Classes' => array("top", "exampleBox"), 'required_fields' => array("cn", "sn", "mail"), 'LDAP_rdn' => 'mail', 'ldap_version' => 3, 'search_fields' => array('mail', 'cn', 'sn', 'givenName'), 'name_field' => 'cn', 'email_field' => 'mail', 'surname_field' => 'sn', 'firstname_field' => 'gn', 'sort' => 'cn', 'scope' => 'sub', 'filter' => '(objectClass=*)', // Construct here any filter you need 'fuzzy_search' => true); $rcmail_config['autocomplete_addressbooks'] = array('sql','example.com');
- 修复 PostfixAdmin 以使用新的表定义
编辑 /var/www/domains/example.com/www/postfixadmin/list-domain.php。替换行:
SELECT domain.* , COUNT( DISTINCT mailbox.username ) AS mailbox_count
使用以下行:
SELECT domain.domain, domain.description, domain.aliases, domain.mailboxes, domain.maxquota, domain.quota, domain.transport, domain.backupmx, domain.created, domain.modified, domain.active, COUNT( DISTINCT mailbox.username ) AS mailbox_count
日志轮换
确保 busybox cron 服务已启动并配置为自动启动
rc-service cron start rc-update add cron default
添加日志轮换
apk add logrotate
根据需要编辑 /etc/logrotate.conf,但默认值对于大多数人来说应该足够了。
可选:配置 Web 服务器虚拟域
注意:除了上面的默认 lighttpd 配置之外,还可以执行这些步骤,这使您可以将 ACF、PostfixAdmin 和 Roundcube 界面作为一个 Web 服务的子文件夹访问。
注意:如果您为多个域站点提供 SSL 访问,您可能需要遵循 https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:SSL#SSL-on-multiple-domains 以提供多域证书。如果您想将主机重定向到其安全等效项,请使用以下说明 https://redmine.lighttpd.net/projects/lighttpd/wiki/HowToRedirectHttpToHttps。
此服务器托管三个独立的 Web 应用程序,这些应用程序可以在同一 Web 服务器上作为三个不同的虚拟域进行处理。它们将通过其 DNS 名称进行区分,因此您可以为三个单独的服务(或至少是您想要发布的那些服务)选择域。
- ACF - 用于管理服务器的 Alpine 配置框架
- PostfixAdmin - 用于管理 postfix 安装
- RoundCube - 用于访问个人邮箱
选择三个不同的域(从此处开始称为 ACF_DOMAIN、POSTFIXADMIN_DOMAIN 和 ROUNDCUBE_DOMAIN),并配置所有三个域的 DNS 以指向您主机的 IP 地址。这些应该是 DNS A 记录。
然后,通过编辑 /etc/lighttpd/lighttpd.conf 配置 lighttpd 以处理三个单独的域。
$HTTP["host"] == "ACF_DOMAIN" { simple-vhost.server-root = "/var/www/domains/" simple-vhost.default-host = "/ACF_DOMAIN/" simple-vhost.document-root = "www/" } $HTTP["host"] == "POSTFIXADMIN_DOMAIN" { simple-vhost.server-root = "/var/www/domains/" simple-vhost.default-host = "/POSTFIXADMIN_DOMAIN/" simple-vhost.document-root = "www/" } $HTTP["host"] == "ROUNDCUBE_DOMAIN" { simple-vhost.server-root = "/var/www/domains/" simple-vhost.default-host = "/ROUNDCUBE_DOMAIN/" simple-vhost.document-root = "www/" }
然后,链接相应的 www 目录。
mkdir -p /var/www/domains/ACF_DOMAIN ln -s /usr/share/acf/www /var/www/domains/ACF_DOMAIN/www mkdir -p /var/www/domains/POSTFIXADMIN_DOMAIN ln -s /var/www/domains/host.example.com/www/postfixadmin /var/www/domains/POSTFIXADMIN_DOMAIN/www mkdir -p /var/www/domains/ROUNDCUBE_DOMAIN ln -s /usr/share/webapps/roundcube /var/www/domains/ROUNDCUBE_DOMAIN/www