Further testing and refinement completed.
This commit is contained in:
parent
c4bdc0164b
commit
0a286ccc1c
@ -55,6 +55,14 @@ Postfix `master.cf` should configure smtpd behavior to require encrypted client
|
||||
|
||||
See [docs/CLIENTS.md](docs/CLIENTS.md) for notes on mail clients.
|
||||
|
||||
## Backups
|
||||
|
||||
See the provided [example](docs/examples/backup.sh) script. Keep in mind that when restoring the `imap.passwd` file for Dovecot, that a new system will have different user ids for maildir. There is a helper to rewrite all the uid/gids to the maildir user when restoring from a backup on a new system:
|
||||
|
||||
```bash
|
||||
ansible-playbook -e 'force_dovecot_passwd_file_maildir_ids=yes' playbooks/mail.yml
|
||||
```
|
||||
|
||||
## Misc
|
||||
|
||||
There are some interesting mta implementations that may replace or compliment parts of this stack in the future:
|
||||
|
@ -8,8 +8,6 @@ dkim_key_path: /etc/dkimkeys
|
||||
#postfix_hostname: "{{ dkim_selector }}.{{ postfix_domain }}"
|
||||
imap_bind_address: "{{ ansible_default_ipv4.address|default(ansible_all_ipv4_addresses[0]) }}"
|
||||
#postfix_maildir_user: maildir
|
||||
postfix_virtual_uid: "{{ ansible_facts.getent_passwd.maildir[1] }}"
|
||||
postfix_virtual_gid: "{{ ansible_facts.getent_group.maildir[1] }}"
|
||||
#postfix_inet_interfaces: all
|
||||
#postfix_mynetworks:
|
||||
# - 127.0.0.0/8
|
||||
@ -42,9 +40,6 @@ postfix_smtpd_client_message_rate_limit: 3
|
||||
postfix_smtpd_client_new_tls_session_rate_limit: 3
|
||||
postfix_smtpd_client_auth_rate_limit: 3
|
||||
|
||||
# robertdebock.dovecot
|
||||
dovecot_mailbox_location: "maildir:{{ postfix_virtual_mailbox_base }}/{{ postfix_domain }}/%n"
|
||||
|
||||
postfix_install:
|
||||
- postfix
|
||||
# - mailutils
|
||||
@ -118,4 +113,9 @@ postfix_smtpd_sasl_path: private/auth
|
||||
postfix_virtual_mailbox_maps: /etc/postfix/vmailbox
|
||||
#postfix_virtual_uid: 1000
|
||||
#postfix_virtual_gid: 1000
|
||||
postfix_maildir_user: maildir
|
||||
postfix_maildir_user: maildir
|
||||
|
||||
force_dovecot_passwd_file_maildir_ids: false # useful when recovering from backup
|
||||
|
||||
# robertdebock.dovecot
|
||||
dovecot_mailbox_location: "maildir:{{ postfix_virtual_mailbox_base }}/{{ postfix_domain }}/%n"
|
||||
|
@ -1,6 +1,15 @@
|
||||
# Mail Server: Deployment
|
||||
|
||||
1. Create MX and TXT records
|
||||
1. Create MX and TXT records. For example, here are example records defined in dnscontrol:
|
||||
```Javascript
|
||||
D('example.com', REG_NAMECHEAP, DnsProvider(DSP_NAMECHEAP),
|
||||
A('mail', '10.87.129.99'),
|
||||
MX('@', 10, 'mail.example.com.'),
|
||||
TXT('_dmarc', 'v=DMARC1; p=none'),
|
||||
TXT('@', 'v=spf1 mx ~all')
|
||||
);
|
||||
```
|
||||
The `A` and `MX` records are required, while the `TXT` records are optional but recommended.
|
||||
|
||||
2. Set a password for the "main" virtual inbox:
|
||||
|
||||
@ -8,11 +17,17 @@
|
||||
echo main:$(doveadm pw -s BLF-CRYPT) >> files/$TARGET/imap.passwd
|
||||
```
|
||||
|
||||
Also, if you use `doas` rather than `sudo`, you need to permit your ansible_user to become opendkim in your `/etc/doas.conf`:
|
||||
|
||||
```
|
||||
permit nopass blee as opendkim
|
||||
```
|
||||
|
||||
3. Copy a vars/targets file, update the values, and run this playbook
|
||||
|
||||
Sanity check opendkim (may need restart):
|
||||
Troubleshooting: Sanity check opendkim (may need restart, although I think I fixed that):
|
||||
```shell
|
||||
l /var/spool/postfix/opendkim/opendkim.sock
|
||||
ls -AlF /var/spool/postfix/opendkim/opendkim.sock
|
||||
```
|
||||
|
||||
4. look at the maildir uid/gid in main.cf and use those in the imap.passwd file (switching to the dovecot role will fix that later)
|
||||
@ -29,9 +44,20 @@
|
||||
|
||||
7. (optional) Create another TXT record for DKIM using the contents of /etc/dkimkeys/mail.txt
|
||||
|
||||
* See [scripts/print-rdata.py](../scripts/print-rdata.py) for an example of how to parse mail.txt
|
||||
* See [octodns](https://github.com/octodns/octodns-easydns) and [dnscontrol](https://dnscontrol.org/)
|
||||
Here's an example line in dnscontrol:
|
||||
|
||||
```Javascript
|
||||
TXT('mail._domainkey', 'v=DKIM1; h=sha256; k=rsa; s=email; p=MIIBIjANB...QIDAQAB')
|
||||
```
|
||||
|
||||
8. (optional) After records propogate, verify outbound mail using: https://www.mail-tester.com/
|
||||
* See [print-rdata.py](examples/print-rdata.py) for a (kind of bad) example of how to automatically parse mail.txt
|
||||
* See [dnscontrol](https://dnscontrol.org/) as well as [octodns](https://github.com/octodns/octodns-easydns)
|
||||
|
||||
If you're really feeling adventurous, you could even set up a proper dmarc address to replace the original placeholder TXT record.
|
||||
|
||||
```Javascript
|
||||
TXT('_dmarc', 'v=DMARC1; p=reject; rua=mailto:dmarc@satstack.cloud; fo=1')
|
||||
```
|
||||
|
||||
After records propogate, verify outbound mail using [mail-tester](https://www.mail-tester.com/).
|
||||
|
||||
|
10
docs/examples/backup.sh
Normal file
10
docs/examples/backup.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
TARGET=mail.example.com
|
||||
|
||||
mkdir -p $HOME/archive/${TARGET}/{dovecot,postfix}
|
||||
rsync -tav root@${TARGET}:/etc/dovecot/imap.passwd $HOME/archive/${TARGET}/
|
||||
rsync -tav root@${TARGET}:/etc/postfix/virtual $HOME/archive/${TARGET}/postfix
|
||||
rsync -tav root@${TARGET}:/etc/dkimkeys $HOME/archive/${TARGET}/
|
||||
rsync -tav root@${TARGET}:/var/vmail $HOME/archive/${TARGET}/
|
13
docs/examples/print-rdata.py
Executable file
13
docs/examples/print-rdata.py
Executable file
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
import zonefile_parser
|
||||
|
||||
with open("mail.txt","r") as stream:
|
||||
content = stream.read()
|
||||
records = zonefile_parser.parse(content)
|
||||
|
||||
for record in records:
|
||||
print()
|
||||
print(f"{record.name}:")
|
||||
print(record.rdata['value'])
|
||||
print()
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
- name: Register Dovecot account database
|
||||
ansible.builtin.file:
|
||||
path: /etc/dovecot/imap.passwd
|
||||
path: "{{ dovecot_passwd_file }}"
|
||||
state: touch
|
||||
owner: root
|
||||
group: dovecot
|
||||
@ -32,3 +32,11 @@
|
||||
src: dovecot.conf.j2
|
||||
dest: /etc/dovecot/local.conf
|
||||
notify: restart dovecot
|
||||
|
||||
- name: Update UID and GID in imap.passwd
|
||||
ansible.builtin.replace:
|
||||
path: "{{ dovecot_passwd_file }}"
|
||||
regexp: '(.*):(\d+):(\d+)$'
|
||||
replace: '\1:{{ maildir_uid }}:{{ maildir_gid }}'
|
||||
when: force_dovecot_passwd_file_maildir_ids
|
||||
notify: restart dovecot
|
@ -32,12 +32,20 @@
|
||||
system: true
|
||||
append: true
|
||||
|
||||
- name: Get maildir user's id
|
||||
- name: Add maildir user's id and group id to ansible_facts
|
||||
ansible.builtin.getent:
|
||||
database: passwd
|
||||
key: "{{ postfix_maildir_user }}"
|
||||
|
||||
- name: Get maildir user's group id
|
||||
ansible.builtin.getent:
|
||||
database: group
|
||||
key: "{{ postfix_maildir_user }}"
|
||||
#- name: Add maildir user's id and group id to ansible_facts
|
||||
# ansible.builtin.getent:
|
||||
# database: "{{ item }}"
|
||||
# key: "{{ postfix_maildir_user }}"
|
||||
# loop:
|
||||
# - passwd
|
||||
# - group
|
||||
|
||||
- name: Set maildir UID and GID
|
||||
set_fact:
|
||||
maildir_uid: "{{ ansible_facts.getent_passwd[postfix_maildir_user][1] }}"
|
||||
maildir_gid: "{{ ansible_facts.getent_passwd[postfix_maildir_user][2] }}"
|
||||
|
@ -21,7 +21,7 @@ service imap-login {
|
||||
# doveadm pw -s BLF-CRYPT
|
||||
passdb {
|
||||
driver = passwd-file
|
||||
args = username_format=%n scheme=blf-crypt /etc/dovecot/imap.passwd
|
||||
args = username_format=%n scheme=blf-crypt {{ dovecot_passwd_file }}
|
||||
auth_verbose=yes
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ passdb {
|
||||
userdb {
|
||||
driver = passwd-file
|
||||
|
||||
args = username_format=%n /etc/dovecot/imap.passwd
|
||||
args = username_format=%n {{ dovecot_passwd_file }}
|
||||
|
||||
default_fields = uid={{ postfix_maildir_user }} gid={{ postfix_maildir_user }}
|
||||
# override_fields =
|
||||
|
@ -17,8 +17,8 @@ virtual_mailbox_base = {{ postfix_virtual_mailbox_base }}/{{ postfix_domain }}
|
||||
virtual_mailbox_maps = {{ postfix_default_database_type }}:{{ postfix_virtual_mailbox_maps }}
|
||||
virtual_mailbox_limit = 0
|
||||
# User: {{ postfix_maildir_user }}
|
||||
virtual_uid_maps = static:{{ postfix_virtual_uid }}
|
||||
virtual_gid_maps = static:{{ postfix_virtual_gid }}
|
||||
virtual_uid_maps = static:{{ maildir_uid }}
|
||||
virtual_gid_maps = static:{{ maildir_gid }}
|
||||
virtual_alias_maps = {{ postfix_default_database_type }}:{{ postfix_virtual_aliases_file }}
|
||||
{% endif %}
|
||||
|
||||
|
@ -21,4 +21,7 @@ postfix_virtual_mailbox_file: /etc/postfix/vmailbox
|
||||
postfix_smtpd_tls_dh1024_param_file: /etc/ssh/dhaparams.pem
|
||||
|
||||
# https://github.com/vdukhovni/postfix/blob/master/postfix/INSTALL
|
||||
postfix_compatibility_level: 3.5 # Debian 11
|
||||
postfix_compatibility_level: 3.5 # Debian 11
|
||||
|
||||
# dovecot
|
||||
dovecot_passwd_file: /etc/dovecot/imap.passwd
|
||||
|
Loading…
Reference in New Issue
Block a user