<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Email on CTmH</title><link>/categories/email/</link><description>Recent content in Email on CTmH</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Wed, 05 Oct 2022 00:00:00 +0000</lastBuildDate><atom:link href="/categories/email/index.xml" rel="self" type="application/rss+xml"/><item><title>安装和配置电子邮件服务端软件 Mailu</title><link>/p/%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE%E7%94%B5%E5%AD%90%E9%82%AE%E4%BB%B6%E6%9C%8D%E5%8A%A1%E7%AB%AF%E8%BD%AF%E4%BB%B6-mailu/</link><pubDate>Wed, 05 Oct 2022 00:00:00 +0000</pubDate><guid>/p/%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE%E7%94%B5%E5%AD%90%E9%82%AE%E4%BB%B6%E6%9C%8D%E5%8A%A1%E7%AB%AF%E8%BD%AF%E4%BB%B6-mailu/</guid><description>&lt;img src="/p/%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE%E7%94%B5%E5%AD%90%E9%82%AE%E4%BB%B6%E6%9C%8D%E5%8A%A1%E7%AB%AF%E8%BD%AF%E4%BB%B6-mailu/mailu_webui.png" alt="Featured image of post 安装和配置电子邮件服务端软件 Mailu" /&gt;&lt;p&gt;Mailu是一个简单但功能齐全的邮件服务器，通过一套Docker镜像来组织服务。当然它是自由软件。该项目提供了一个易于设置、易于维护和功能齐全的邮件服务器，同时不提供专有软件中经常出现的无关功能。&lt;/p&gt;&#10;&lt;p&gt;建议以开发者给出的&lt;a class="link" href="https://mailu.io/" target="_blank" rel="noopener"&#10; &gt;文档&lt;/a&gt;为主要参考，本文仅作为补充。本文安装的版本是1.9稳定版。写下本文时，podman-compose还不能正确解析mailu的&lt;code&gt;docker-compose.yml&lt;/code&gt;文件中的子网设置部分，因此除非后续podman-compose更新解决这一问题，否则不要用podman来替代docker。安装docker的方法此处略过。&lt;/p&gt;&#10;&lt;h1 id="配置dns"&gt;配置DNS&#10;&lt;/h1&gt;&lt;p&gt;访问域名供应商或者DNS服务供应商。向DNS中添加&lt;strong&gt;A&lt;/strong&gt;类记录。&lt;code&gt;a.b.c.d&lt;/code&gt;是服务器的地址。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;mail.mydomain.com. IN A a.b.c.d&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;再添加一条&lt;strong&gt;MX&lt;/strong&gt;类记录，指向服务器&lt;code&gt;mail.mydomain.com&lt;/code&gt;。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;mydomain.com. IN MX 10 mail.mydomain.com.&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;再访问VPS供应商，写入一条rDNS记录。rDNS记录是从IP地址&lt;code&gt;a.b.c.d&lt;/code&gt;到域名&lt;code&gt;mail.mydomain.com&lt;/code&gt;的反向解析，因此需要通过VPS供应商来设置。&lt;/p&gt;&#10;&lt;h1 id="配置防火墙"&gt;配置防火墙&#10;&lt;/h1&gt;&lt;p&gt;通过SSH连接到服务器后，首先配置防火墙。可以选择安装ufw来间接配置或者直接配置iptables，我觉得ufw更加方便。配置防火墙需要以root身份或使用sudo。&lt;/p&gt;&#10;&lt;p&gt;ufw自带了根据应用预设的防火墙配置，需要打开其中的&lt;code&gt;OpenSSH&lt;/code&gt;、&lt;code&gt;Nginx Full&lt;/code&gt;、&lt;code&gt;Mail submission&lt;/code&gt;、&lt;code&gt;SMTP&lt;/code&gt;、&lt;code&gt;POP3&lt;/code&gt;、&lt;code&gt;POP3S&lt;/code&gt;、&lt;code&gt;IMAP&lt;/code&gt;、&lt;code&gt;IMAPS&lt;/code&gt;。注意&lt;code&gt;OpenSSH&lt;/code&gt;一定要打开，否则会和服务器丢失连接，如果修改过SSH的端口，也要记得打开相应端口。除了以上预设配置外，需要额外开启端口&lt;code&gt;465&lt;/code&gt;用于TLS的SMTP通信、端口&lt;code&gt;587&lt;/code&gt;用于STARTLS的SMTP通信，端口&lt;code&gt;5432&lt;/code&gt;用于Mailu从其容器中访问Postgresql。ufw添加规则的方法如下。&lt;/p&gt;&#10;&lt;p&gt;添加预设规则（如&lt;code&gt;Mail submission&lt;/code&gt;）：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo ufw allow &amp;quot;Mail submission&amp;quot;&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;打开指定端口（如&lt;code&gt;465&lt;/code&gt;）的TCP功能：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo ufw allow 465/tcp&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;添加后使用以下命令查看规则。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo ufw status numbered&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;根据以上命令列出的规则编号删除规则。比如删除11号规则：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo ufw delete 11&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;以上命令删除多个规则时，不能一次填写多个编号。由于删除规则后规则编号会变化，需要重新查看规则编号，修改后再次执行以上命令。&lt;/p&gt;&#10;&lt;p&gt;设置好规则后激活生效。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo ufw enable&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;h1 id="安装和配置postgresql"&gt;安装和配置Postgresql&#10;&lt;/h1&gt;&lt;p&gt;为了方便，我也使用docker来安装postgresql数据库管理软件。以下的配置里Postgresql的容器和Mailu的容器运行在同一个服务器上。&lt;/p&gt;&#10;&lt;p&gt;使用docker时需要以root身份或使用sudo，本文中的docker相关操作都通过sudo运行。为了方便之后的配置，这里最好使用默认端口号5432。注意替换&lt;code&gt;POSTGRES_PASSWORD=your-password&lt;/code&gt;部分。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo docker run -it --name postgresql-default --restart always -e POSTGRES_PASSWORD=your-password -v /srv/postgresql-data:/var/lib/postgresql/data -e POSTGRES_INITDB_ARGS=&amp;quot;--data-checksums&amp;quot; -p 5432:5432 postgres&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;连接到docker中配置数据库&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo docker exec -it postgresql-default psql -U postgres -d postgres&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;之后创建mailu用户和相应的数据库。注意替换&lt;code&gt;my_secure_pass&lt;/code&gt;部分。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;postgres=# create user mailu;&#10;postgres=# alter user mailu password 'my_secure_pass';&#10;postgres=# create database mailu owner mailu;&#10;postgres=# \c mailu&#10;mailu=# create extension citext;&#10;mailu=# \q&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;注意记录数据库用户mailu的密码。由于Mailu服务的各个容器位于另一个子网中，为了Mailu能够顺利访问数据库，需要设置Postgresql的访问权限。&lt;/p&gt;&#10;&lt;p&gt;在当前目录创建&lt;code&gt;pg_hba.conf&lt;/code&gt;文件，其中的内容类似于：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;# TYPE DATABASE USER ADDRESS METHOD&#10;&#10;# &amp;quot;local&amp;quot; is for Unix domain socket connections only&#10;local all all trust&#10;# IPv4 local connections:&#10;host all all 127.0.0.1/32 trust&#10;# IPv6 local connections:&#10;host all all ::1/128 trust&#10;# Allow replication connections from localhost, by a user with the&#10;# replication privilege.&#10;local replication all trust&#10;host replication all 127.0.0.1/32 trust&#10;host replication all ::1/128 trust&#10;host mailu mailu 172.17.0.0/16 md5&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;注意将类似&lt;code&gt;host all all all scram-sha-256&lt;/code&gt;的部分删除，阻止其他远程访问请求。限定除了本机通信外（如&lt;code&gt;127.0.0.1/32&lt;/code&gt;和&lt;code&gt;::1/128&lt;/code&gt;），只有用户&lt;code&gt;mailu&lt;/code&gt;能从Docker的网段&lt;code&gt;172.17.0.0/16&lt;/code&gt;访问数据库&lt;code&gt;mailu&lt;/code&gt;。&#10;然后将配置文件覆盖到Postgresql的容器中并重启数据库。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo docker cp ~/pg_hba.conf postgresql-default:/var/lib/postgresql/data/pg_hba.conf&#10;sudo docker restart postgresql-default&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;为了验证数据库可用，可以尝试在服务器的Shell中尝试连接到数据库。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;psql -U mailu -d mailu -h 127.0.0.1&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;h1 id="生成mailu配置文件"&gt;生成Mailu配置文件&#10;&lt;/h1&gt;&lt;p&gt;Mailu的开发者们提供了一个&lt;a class="link" href="https://setup.mailu.io/" target="_blank" rel="noopener"&#10; &gt;Web应用&lt;/a&gt;来生成配置文件。开发者提供了配置建议，非常方便。需要注意的是 &lt;em&gt;TLS certificates&lt;/em&gt; 、&lt;em&gt;Database preferences&lt;/em&gt; 和 &lt;em&gt;IPv4 listen address&lt;/em&gt; 选项。&lt;/p&gt;&#10;&lt;p&gt;由于我打算使用外置的Nginx服务器作为反向代理，因此 &lt;em&gt;TLS certificates&lt;/em&gt; 可以选择 &lt;code&gt;mail&lt;/code&gt; 或者 &lt;code&gt;mail-letsencrypt&lt;/code&gt; 。这两个选项意味着将Web的TLS交给反向代理服务器来处理，Mailu的Web服务只需处理HTTP协议的通信，而IMAP、POP、SMTP的TLS还是由Mailu来处理。选项 &lt;code&gt;mail&lt;/code&gt; 意味着使用手动安装的证书，需要在 &lt;em&gt;Mailu storage path&lt;/em&gt; 项目里填写的目录下创建 &lt;code&gt;certs&lt;/code&gt; 文件夹，并在其中安装证书文件&lt;code&gt;cert.pem&lt;/code&gt;和密钥文件&lt;code&gt;key.pem&lt;/code&gt;。当然也可以在之后生成的&lt;code&gt;mailu.env&lt;/code&gt;文件中通过变量&lt;code&gt;TLS_CERT_FILENAME&lt;/code&gt;和&lt;code&gt;TLS_KEYPAIR_FILENAME&lt;/code&gt;来更改这两个文件的名称。如果选择&lt;code&gt;mail-letsencrypt&lt;/code&gt;，则Mailu服务会自动申请并安装证书。服务器上没有其他占用80和443端口的服务时，可以不使用反向代理，此时这里可以选择&lt;code&gt;letsencrypt&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;如果和我一样使用外置的Postgresql数据库管理软件，则在&lt;em&gt;Database preferences&lt;/em&gt;中选择&lt;code&gt;postgresql&lt;/code&gt;并填写上一步里配置的信息即可。注意在数据库的地址栏中要填写数据库的真实地址，不要填写&lt;code&gt;127.0.0.1&lt;/code&gt;。也不要添加端口号，如果在地址里添加了端口号（如&lt;code&gt;1.1.1.1:5432&lt;/code&gt;），会导致后续解析数据库地址时出错，因此之前配置数据库时建议不要更改默认端口。&lt;/p&gt;&#10;&lt;p&gt;Mailu的开发者建议在 &lt;em&gt;IPv4 listen address&lt;/em&gt; 中填写实际的IPv4地址。注意在此处填写实际IPv4地址时，Nginx的配置需要做针对性修改，在下文中将会说明。&lt;/p&gt;&#10;&lt;p&gt;为了方便使用，我选择安装了WebUI（对应选项&lt;code&gt;WebMail&lt;/code&gt;）和管理员后台AdminUI。在&lt;code&gt;WebMail&lt;/code&gt;处可以根据喜好选择两种不同风格的UI。&lt;/p&gt;&#10;&lt;p&gt;根据提示填写完所有信息后，点击生成按钮。此时根据跳转后页面中Step1的提示，创建项目文件夹并下载生成的配置文件&lt;code&gt;docker-compose.yml&lt;/code&gt;和&lt;code&gt;mailu.env&lt;/code&gt;。此时先不要按Step3操作。&lt;/p&gt;&#10;&lt;h1 id="配置nginx服务器"&gt;配置Nginx服务器&#10;&lt;/h1&gt;&lt;p&gt;由于服务器上会运行各不相同的服务，相应的配置也千差万别，因此本节仅说明配置Nginx作为反向代理时可能出错的地方。如果不想使用反向代理，可以直接跳过这一节。&lt;/p&gt;&#10;&lt;p&gt;首先修改之前生成并下载到本地的配置文件&lt;code&gt;docker-compose.yml&lt;/code&gt;。找到&lt;code&gt;# Core services&lt;/code&gt;部分，修改容器中的&lt;code&gt;80&lt;/code&gt;和&lt;code&gt;443&lt;/code&gt;在服务器上对应的端口，比如我改为了&lt;code&gt;8080&lt;/code&gt;和&lt;code&gt;8443&lt;/code&gt;。这样就不会和监听&lt;code&gt;80&lt;/code&gt;和&lt;code&gt;443&lt;/code&gt;端口的Nginx冲突。修改后的&lt;code&gt;ports&lt;/code&gt;前两行如下：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;ports:&#10; - &amp;quot;x.x.x.x:8080:80&amp;quot;&#10; - &amp;quot;x.x.x.x:8443:443&amp;quot;&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;修改&lt;code&gt;mailu.env&lt;/code&gt;文件中的&lt;code&gt;REAL_IP_HEADER&lt;/code&gt;和&lt;code&gt;REAL_IP_FROM&lt;/code&gt;部分。&lt;code&gt;x.x.x.x&lt;/code&gt;替换为服务器真实IPv4地址。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;REAL_IP_HEADER=X-Real-IP&#10;REAL_IP_FROM=x.x.x.x&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;此处给出Nginx配置文件的一种写法，更多的配置模板请参考&lt;a class="link" href="https://mailu.io/1.9/reverse.html#have-mailu-web-frontend-listen-locally" target="_blank" rel="noopener"&#10; &gt;文档&lt;/a&gt;。修改Nginx配置后需要重新加载Nginx服务。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;server {&#10; listen 443 ssl http2 reuseport;&#10; server_name mail.yourdomain.com;&#10; charset utf-8;&#10;&#10; # ssl&#10; ssl_protocols TLSv1.2 TLSv1.3;&#10; ssl_prefer_server_ciphers on;&#10; ssl_session_cache shared:SSL:40m;&#10; ssl_session_timeout 5m;&#10; ssl_session_tickets off;&#10; ssl_certificate /path/to/fullchain.pem;&#10; ssl_certificate_key /path/to/privkey.pem;&#10;&#10; # OCSP stapling&#10; ssl_stapling on;&#10; ssl_stapling_verify on;&#10;&#10; add_header Strict-Transport-Security &amp;quot;max-age=63072000&amp;quot;;&#10;&#10; location / {&#10; proxy_set_header Host $host;&#10; proxy_set_header X-Real-IP $remote_addr;&#10; proxy_set_header WL-Proxy-SSL true;&#10; proxy_set_header X-Forwarded-For $remote_addr;&#10; client_max_body_size 64M;&#10; proxy_pass http://a.b.c.d:8080;&#10; }&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;&lt;code&gt;server_name&lt;/code&gt;处需要根据之前的DNS记录填写，&lt;code&gt;ssl_certificate&lt;/code&gt;和&lt;code&gt;ssl_certificate_key&lt;/code&gt;处需要填写SSL证书的路径。如果还没有证书，可以通过&lt;a class="link" href="https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E" target="_blank" rel="noopener"&#10; &gt;acme.sh&lt;/a&gt;获取证书。此处略过获取证书的过程。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;location&lt;/code&gt;中的&lt;code&gt;proxy_set_header&lt;/code&gt;参照以上例子填写即可。但需要特别注意&lt;code&gt;proxy_pass&lt;/code&gt;后需要填写服务器的&lt;strong&gt;真实IPv4地址&lt;/strong&gt;，而&lt;strong&gt;不能&lt;/strong&gt;填写&lt;code&gt;127.0，0，1&lt;/code&gt;之类的地址，后续遇到&lt;strong&gt;502错误&lt;/strong&gt;时可以重点检查此处的信息是否填写正确。&lt;/p&gt;&#10;&lt;h1 id="安装和运行mailu容器"&gt;安装和运行Mailu容器&#10;&lt;/h1&gt;&lt;p&gt;确认配置文件无误后按照Step3的提示进入项目目录并启动服务。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;cd /srv/mailu&#10;sudo docker-compose -p mailu up -d&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;服务启动后添加管理员用户，以&lt;code&gt;adminuser&lt;/code&gt;为例。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo docker-compose -p mailu exec admin flask mailu admin adminuser yourdomain.com PASSWORD&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;参照Step3的说明，&lt;code&gt;PASSWORD&lt;/code&gt;处的初始密码可以在之后进入管理界面修改。如果在添加用户这一步报错，并提示无法访问Postgresql，需要检查Postgresql的访问设置&lt;code&gt;pg_hba.conf&lt;/code&gt;和防火墙的设置。先关闭Mailu服务。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo docker-compose -p mailu down&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;修改相关设置后重启服务。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo docker-compose -p mailu up -d&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;如果添加用户过程中出现过错误，需要删除Postgresql中的数据库&lt;code&gt;mailu&lt;/code&gt;并按照上文中的方法新建数据库&lt;code&gt;mailu&lt;/code&gt;，否则会遇到Postgresql找不到域(Domain)的错误。&lt;/p&gt;&#10;&lt;p&gt;之后可以添加一个普通用户（比如&lt;code&gt;myuser&lt;/code&gt;）来测试收发邮件是否正常。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;sudo docker-compose exec admin flask mailu user myuser yourdomain.com 'password123'&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;用网页访问mail.mydomain.com，登陆后即可测试相关功能。&lt;/p&gt;&#10;&lt;h1 id="维护服务器"&gt;维护服务器&#10;&lt;/h1&gt;&lt;p&gt;后续维护和功能设置可以参考&lt;a class="link" href="https://mailu.io/1.9/maintain.html" target="_blank" rel="noopener"&#10; &gt;文档&lt;/a&gt;。&lt;/p&gt;</description></item></channel></rss>