314 lines
10 KiB
Markdown
314 lines
10 KiB
Markdown
# Ansible Collection - s3lph.mailserver
|
|
|
|
## Roles
|
|
|
|
- `s3lph.mailserver.postfix`: [Postfix][postfix] mail server
|
|
- `s3lph.mailserver.postsrsd`: [PostSRSd][postsrsd] Sender Rewriting Scheme daemon for Postfix
|
|
- `s3lph.mailserver.postfixadmin`: [PostfixAdmin][postfixadmin] PHP mnmagement interface for mailboxes and aliases
|
|
- `s3lph.mailserver.spamassassin`: [SpamAssassin][spamassassin] spam filter
|
|
- `s3lph.mailserver.mailman`: [Mailman 3][mailman] mailing list server, management and archive interface
|
|
- `s3lph.mailserver.dovecot`: [Dovecot][dovecot] IMAP server
|
|
- `s3lph.mailserver.schleuder`: [Schleuder][schleuder] PGP-encrypted mailing list server
|
|
- `s3lph.mailserver.easywks`: [EasyWKS][easywks] server
|
|
- `s3lph.mailserver.multischleuder`: [Multischleuder][multischleuder] Schleuder management
|
|
|
|
## Status of This Collection
|
|
|
|
This collection is designed to work with Debian >= 11, but it should
|
|
work on any Debian-based distribution.
|
|
|
|
The roles in this collection are currently mainly designed to work in
|
|
unison with each other. They can be used to set up a production-ready
|
|
mail server IF setting up at least Postfix, PostfixAdmin and Dovecot.
|
|
|
|
If only some parts are used, there may be some restrictions in place,
|
|
such as:
|
|
- Virtual mail domains currently can't be configured
|
|
- Overriding defaults for master.cf entries currently is rather
|
|
cumbersome (see below)
|
|
|
|
Documentation is not yet where it should be, but it's getting there.
|
|
|
|
## Example Setup
|
|
|
|
The following example is a collection of host vars that will get your
|
|
mail stack up and running.
|
|
|
|
### Postfix
|
|
|
|
```yaml
|
|
# The default "3.6" is too recent for e.g. Debian buster
|
|
postfix_compatibility_level: 2
|
|
# General domain settings
|
|
postfix_mydomain: example.org
|
|
postfix_myorigin: "$myhostname"
|
|
# Set up TLS
|
|
postfix_smtpd_tls_cert_file: "/etc/ssl/certs/{{ inventory_hostname }}.crt"
|
|
postfix_smtpd_tls_key_file: "/etc/ssl/private/{{ inventory_hostname }}.key"
|
|
# The smtpd_*_restrictions in this role are fairly restrictive.
|
|
# If you need to override this, you can do so e.g. through this:
|
|
postfix_smtpd_client_restrictions:
|
|
- reject_unauth_pipelining
|
|
- permit_mynetworks
|
|
- reject_non_fqdn_sender
|
|
- reject_unknown_sender_domain
|
|
- permit
|
|
# This goes into /etc/aliases
|
|
postfix_aliases:
|
|
root: me
|
|
abuse: me
|
|
postmaster: you
|
|
hostmaster: me you them
|
|
# Unfortunately I haven't come up with a better way to manage master.cf
|
|
# entries yet, so this will have to do for now:
|
|
postfix_master_processes: |
|
|
# Override TLS certificate for the submission port
|
|
{%- set x = postfix_default_master_processes.submission.options.append("-o smtpd_tls_cert_file=/etc/ssl/certs/smtp.example.org.crt") -%}
|
|
{%- set x = postfix_default_master_processes.submission.options.append("-o smtpd_tls_key_file=/etc/ssl/private/smtp.example.org.key") -%}
|
|
{{ postfix_default_master_processes }}
|
|
```
|
|
|
|
Also includes support for postfix-policyd-spf-python. To enable, set
|
|
|
|
```yaml
|
|
postfix_policyd_spf_enable: yes
|
|
postfix_smtpd_recipient_restrictions:
|
|
# ...
|
|
- reject_unauth_destination
|
|
- check_policy_service unix:private/policyd-spf
|
|
# ...
|
|
```
|
|
|
|
Run `ansible-playbook -t role::postfix` to deploy.
|
|
|
|
### PostSRSd
|
|
|
|
```yaml
|
|
# Tell Postfix to pass all mails through PostSRSd
|
|
postfix_srsd_enable: yes
|
|
|
|
# Use a domain that your MX can send and receive mail for
|
|
postsrsd_domain: srs.example.org
|
|
```
|
|
|
|
Run `ansible-playbook -t role::postfix:config,role::postsrsd` to
|
|
deploy. Note that Postfix must already be up and running with a valid
|
|
config, because `PostSRSd` uses the `postconf` command to obtain
|
|
additional information.
|
|
|
|
### PostfixAdmin
|
|
|
|
```yaml
|
|
# Configure Postfix to get virtual mail config from PostfixAdmin's
|
|
# MariaDB backend
|
|
postfix_postfixadmin_enable: yes
|
|
|
|
# Postfix is running chrooted, and bind-mounting the socket into
|
|
# /var/spool/postfix is messy
|
|
postfixadmin_database_postfix_hosts: 127.0.0.1
|
|
# Configure global aliases
|
|
postfixadmin_admin_name: You
|
|
postfixadmin_admin_email: postmaster@example.org
|
|
# Configure mail delivery transports (only required if other
|
|
# transports than "virtual" are used)
|
|
postfixadmin_transport: yes
|
|
postfixadmin_transport_options:
|
|
# Need to use LMTP instead of virtual delivery for Sieve to work
|
|
- lmtp:unix:private/dovecot-lmtp
|
|
# Base URL is needed to call the bootstrap API
|
|
postfixadmin_base_url: https://example.org/postfixadmin
|
|
|
|
# If set to yes/true, this option permits login for inactive users, but only if the service is NOT smtp.
|
|
# This permits disabled users to still read their mail, but will not allow them to send mail.
|
|
postfixadmin_permit_inactive_user_nosmtp: yes
|
|
```
|
|
|
|
As this role involves some secrets, you should put the following
|
|
variables into a protected location, e.g. an ansible-vault encrypted
|
|
file:
|
|
|
|
```yaml
|
|
postfixadmin_setup_password: super secure setup password
|
|
|
|
# Admin user used for invoking the bootstrap API endpoint
|
|
postfixadmin_bootstrap_admin_username: postmaster@example.org
|
|
postfixadmin_bootstrap_admin_password: another secure password
|
|
|
|
# The postfixadmin user will be able to read/write
|
|
postfixadmin_database_password: 2097uogd94WNayeo
|
|
# The postfix and dovecot users will be readonly
|
|
postfixadmin_database_postfix_password: Oh5r0RJcVzDIqjP4
|
|
postfixadmin_database_dovecot_password: c9yFPDDBuL3ft4FD
|
|
```
|
|
|
|
The web server config is not (yet) managed with Ansible. You can
|
|
e.g. set up Apache with PHP integration and alias a URL path to the
|
|
PostfixAdmin webroot:
|
|
|
|
```apache2
|
|
Alias /admin /opt/postfixadmin/postfixadmin/public
|
|
```
|
|
|
|
If MariaDB is running on the same host, you can bootstrap the database
|
|
and its users automatically:
|
|
|
|
1. `ansible-playbook -t role::postfixadmin`
|
|
1. `ansible-playbook -t role::postfixadmin:bootstrap` (tagged with
|
|
`never` so needs to be invoked explicitly)
|
|
1. `ansible-playbook -t role::postfix:config`
|
|
|
|
### SpamAssassin
|
|
|
|
```yaml
|
|
# Tell postfix to pass mails through spamassassin
|
|
postfix_spamassassin_enable: yes
|
|
|
|
# Configure spamassassin daemon for using only global config
|
|
spamassassin_spamd_user: debian-spamd
|
|
spamassassin_nouser_config: yes
|
|
# Enable daily rule update
|
|
spamassassin_enable_cron: yes
|
|
# Configure internal network addresses
|
|
spamassassin_internal_networks:
|
|
- "2001:db8:42::10"
|
|
- "10.42.0.10"
|
|
spamassassin_trusted_networks:
|
|
- "2001:db8:23::10"
|
|
- "10.23.0.10"
|
|
# Additional SpamAssassin config, e.g. rule definitions or overrides
|
|
postfix_spamassassin_enable: |
|
|
# Override score for a rule
|
|
score FREEMAIL_FORGED_REPLYTO 3.5
|
|
# Rule that checks for common german load-related spammy words
|
|
body __LOANS_GERMAN_1 /darlehen/i
|
|
body __LOANS_GERMAN_2 /kredite?/i
|
|
body __LOANS_GERMAN_3 /zinss.{0,3}tz/i
|
|
meta LOANS_GERMAN ((__LOANS_GERMAN_1 + __LOANS_GERMAN_2 + __LOANS_GERMAN_3) > 1)
|
|
describe LOANS_GERMAN Loans offered in German
|
|
score LOANS_GERMAN 2.0
|
|
```
|
|
|
|
Run `ansible-playbook -t role::postfix:config,role::postsrsd` to deploy.
|
|
|
|
### Mailman 3
|
|
|
|
```yaml
|
|
# Tell postfix to pass mailing list addresses to mailman
|
|
postfix_mailman_enable: yes
|
|
|
|
# Postfix is running chrooted, and bind-mounting the socket into
|
|
# /var/spool/postfix is messy
|
|
mailman_database_postfix_hosts: 127.0.0.1
|
|
# Configure names, URLs and mail addresses
|
|
mailman_sitename: lists.example.org
|
|
mailman_site_owner: mailman@example.org
|
|
mailman_web_base_url: https://lists.example.org/
|
|
mailman_web_admin_name: Mailman Admin
|
|
mailman_web_admin_email: mailman@example.org
|
|
# Initial admin account to create on bootstrap
|
|
mailman_superuser_name: root
|
|
mailman_superuser_email: mailman@example.org
|
|
```
|
|
|
|
As this role involves some secrets, you should put the following
|
|
variables into a protected location, e.g. an ansible-vault encrypted
|
|
file:
|
|
|
|
```yaml
|
|
# Generate secure passwords for all these values
|
|
mailman_mariadb_password:
|
|
mailman_webservice_admin_pass:
|
|
mailman_web_database_password:
|
|
mailman_superuser_password: # <-- you'll need this later to log in
|
|
mailman_hyperkitty_api_key:
|
|
mailman_web_secret_key:
|
|
mailman_database_postfix_password:
|
|
```
|
|
|
|
If MariaDB is running on the same host, you can bootstrap the database
|
|
and its users automatically:
|
|
|
|
1. `ansible-playbook -t role::mailman`
|
|
1. `ansible-playbook -t role::mailman:bootstrap` (tagged with
|
|
`never` so needs to be invoked explicitly)
|
|
1. `ansible-playbook -t role::postfix:config`
|
|
|
|
|
|
### Dovecot
|
|
|
|
```yaml
|
|
dovecot_hostname: imap.example.org
|
|
dovecot_tls_cert_filename: /etc/ssl/certs/imap.example.org.crt
|
|
dovecot_tls_key_filename: /etc/ssl/private/imap.example.org.key
|
|
# Enable Pigeonhole Sieve/ManageSieve
|
|
dovecot_enable_pigeonhole: yes
|
|
dovecot_enable_pigeonhole_managesieve: yes
|
|
# Adapt to your virtual mail home
|
|
dovecot_pigeonhole_sieve: 'file:/home/virtual/%d/%n/sieve;active=/home/virtual/%d/%n/.dovecot.sieve'
|
|
```
|
|
|
|
Run `ansible-playbook -t role::dovecot` to deploy
|
|
|
|
### Schleuder
|
|
|
|
TODO: Documentation/Example
|
|
|
|
### EasyWKS
|
|
|
|
```yaml
|
|
# Register a "gpgwks" postfix transport in master.cf, which pipes
|
|
# mail into easywks process. LMTP should be preferred though!
|
|
#postfix_easywks_pipe_transport: yes
|
|
|
|
# When the easywks package is available in your system's package
|
|
# sources, set this to no. Otherwise the package is downloaded from
|
|
# the project upstream releases at Gitlab.
|
|
#easywks_download: no
|
|
|
|
# Simple /etc/easywks.yml encoded as a multiline string
|
|
easywks_config: |
|
|
mailing_method: smtp
|
|
smtp:
|
|
host: localhost
|
|
port: 8025
|
|
lmtpd:
|
|
host: "::1"
|
|
port: 8024
|
|
domains:
|
|
example.org:
|
|
submission_address: webkey@example.org
|
|
example.net:
|
|
submission_address: wks@example.net
|
|
```
|
|
|
|
Run `ansible-playbook -t role::postfix:config,role::easywks` to deploy
|
|
|
|
|
|
### Multischleuder
|
|
|
|
```yaml
|
|
# When the multischleuder package is available in your system's package
|
|
# sources, set this to no. Otherwise the package is downloaded from
|
|
# the project upstream releases at Gitlab.
|
|
#multischleuder_download: no
|
|
|
|
# Simple /etc/multischleuder/multischleuder.yml encoded as a multiline string
|
|
mutlischleuder_config: |
|
|
api:
|
|
url: "https://localhost:4443"
|
|
token: "thetoken"
|
|
cafile: /etc/multischleuder/schleuder-ca.pem
|
|
# See https://gitlab.com/s3lph/multischleuder for the full config...
|
|
```
|
|
|
|
Run `ansible-playbook -t role::multischleuder` to deploy
|
|
|
|
[postfix]: http://www.postfix.org/
|
|
[postsrsd]: https://github.com/roehling/postsrsd
|
|
[postfixadmin]: https://github.com/postfixadmin/postfixadmin
|
|
[spamassassin]: https://spamassassin.apache.org/
|
|
[mailman]: http://list.org/
|
|
[dovecot]: https://dovecot.org/
|
|
[schleuder]: https://schleuder.org/
|
|
[easywks]: https://gitlab.com/s3lph/easywks
|
|
[multischleuder]: https://gitlab.com/s3lph/multischleuder
|