dovecot & postfix servers
Install and configure dovecot (imap) and postfix (smtp)
servers, co-deployed to share authentication.
spamassassin is also installed to filter junk mail.
2021-06-11 Ubuntu 20.04
Overall configuration across the servers:
Domain user
user @domain
Mailbox
/var/mail/vhosts/domain /user /Maildir/
Authentication
Managed by dovecot , channel for postfix at
/var/spool/postfix/private/auth
User lookup
/var/mail/vhosts/domain /passwd
Password lookup
/var/mail/vhosts/domain /shadow
The example being used is to add domain user fred.nerk@geddy.au .
The server domain names are assumed to be set up as:
s1.geddy.au
Host on which the servers co-reside.
smtp.geddy.au
smtp server, pointing at s1.geddy.au
.
It must have a DNS A record not a DNS CNAME record to
s1.geddy.au
– this is part of the security
paradigm between open internet smtp servers.
imap.geddy.au
imap server, pointing at s1.geddy.au
.
pop.geddy.au
pop server, pointing at s1.geddy.au
.
postfix
graham:~ sudo vi /etc/hostname
/etc/hostname
replace all content
smtp
graham:~ sudo hostname smtp
graham:~ sudo vi /etc/hosts
/etc/hosts
add/update single setting
127.0.1.1 smtp.geddy.au
graham:~ hostname --all-fqdns
smtp.geddy.au
Verify fully qualified domain name is correct.
graham:~ sudo apt update
graham:~ sudo apt install postfix mailutils bsd-mailx libsasl2-modules
Select Satellite site in popup configuration,
though it matters not what option is selected –
it is about to be completely overwritten anyway.
graham:~ sudo systemctl stop postfix # stop postfix for updating
graham:~ sudo vi /etc/postfix/main.cf
/etc/postfix/main.cf
replace all content
# Virtual Domain Postfix (geddy.au )
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
# A safety net that causes Postfix to run with
# backwards-compatible default settings after an upgrade to a newer Postfix
# version. See http://www.postfix.org/COMPATIBILITY_README.html.
#
# new installs: set to 2
compatibility_level = 2
# The UNIX system account that owns the Postfix queue and most Postfix daemon
# processes. Specify the name of an unprivileged user account that does not
# share a user or group ID with other accounts, and that owns no other files
# or processes on the system. In particular, don't specify nobody or daemon.
# PLEASE USE A DEDICATED USER ID AND GROUP ID.
#
# default, leave un-commented
#mail_owner = postfix
# The group ownership of set-gid Postfix commands and of group-writable
# Postfix directories.
#
# default, leave commented-out
#setgid_group = postdrop
##::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
## MTA Identification
##::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# The internet hostname of this mail system.
#
myhostname = smtp.geddy.au
# The domain name that locally-posted mail appears to come from,
# and that locally posted mail is delivered to.
#
# default, leave commented-out
#myorigin = /etc/mailname
# The list of domains that are delivered via the $local_transport mail
# delivery transport.
#
mydestination =
$myhostname localhost localhost.$mydomain
smtp.geddy.au
s1.$mydomain
# ^ note that domains are listed in virtual_mailbox_domains *instead*
# The list of "trusted" remote SMTP clients that have more privileges
# than "strangers". In particular, "trusted" SMTP clients are allowed
# to relay mail through Postfix.
#
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
##::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
## LOCAL RECEIVE
##::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
## SENDMAIL(1) :::::::::::::::::::::::::::::::::::::::::::::::::::::::
##::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
## LOCAL DELIVERY
##::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
## LOCAL(8) - LOCAL MAIL DELIVERY ::::::::::::::::::::::::::::::::::::
## Compatability
# Whether or not to use the local biff service.
#
biff = no
## Delivery Method
# The alias databases that are used for local(8) delivery.
#
alias_maps = hash:/etc/aliases
# The alias databases for local(8) delivery that are updated with
# "newaliases" or with "sendmail -bi". This is a separate configuration
# parameter because not all the tables specified with $alias_maps have to
# be local files.
#
alias_database = hash:/etc/aliases
# The set of characters that can separate a user name from its
# extension (example: user+foo), or a .forward file name from its
# extension (example: .forward+foo).
#
recipient_delimiter = +
## Resource Controls
# The maximal size of any local(8) individual mailbox or maildir
# file, or zero (no limit).
#
mailbox_size_limit = 0
# The maximal size in bytes of a message, including envelope information.
#
#message_size_limit = 120480000
## TRIVIAL-REWRITE(8) ::::::::::::::::::::::::::::::::::::::::::::::::
## Address Rewriting Rules
# With locally submitted mail, append the string ".$mydomain" to
# addresses that have no ".domain" information.
#
append_dot_mydomain = no
##::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
## NETWORK RECEIVE
##::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# The network interface addresses that this mail system receives mail on.
# The parameter also controls delivery of mail to user@[ip.address].
#
inet_interfaces = all
# The Internet protocols Postfix will attempt to use when making or
# accepting connections.
#
#inet_protocols = all
inet_protocols = ipv4
## SMTPD(8) - SMTP SERVER ::::::::::::::::::::::::::::::::::::::::::::
## Compatability
# Enable interoperability with remote SMTP clients that implement
# an obsolete version of the AUTH command (RFC 4954).
#
broken_sasl_auth_clients = yes
# Disable the SMTP VRFY command.
#
disable_vrfy_command = yes
# Require that addresses received in SMTP MAIL FROM and RCPT TO
# commands are enclosed with <>, and that those addresses do not
# contain RFC 822 style comments or phrases.
#
strict_rfc821_envelopes = yes
## SASL
# Enable SASL authentication in the Postfix SMTP server.
#
smtpd_sasl_auth_enable = yes
# The name of the Postfix SMTP server's local SASL authentication
# realm.
#
smtpd_sasl_local_domain = $mydomain
# Postfix SMTP server SASL security options; as of Postfix 2.3 the
# list of available features depends on the SASL server implemen-
# tation that is selected with smtpd_sasl_type.
#
smtpd_sasl_security_options = noanonymous
# Implementation-specific information that the Postfix SMTP client
# passes through to the SASL plug-in implementation that is
# selected with smtp_sasl_type.
#
smtpd_sasl_path = private/auth
# The SASL plug-in type that the Postfix SMTP client should use
# for authentication.
#
smtpd_sasl_type = dovecot
## STARTTLS
# The SMTP TLS security level for the Postfix SMTP server; when a
# non-empty value is specified, this overrides the obsolete param-
# eters smtpd_use_tls and smtpd_enforce_tls.
#
# select one:
# STARTTLS
smtpd_tls_security_level = may
# SSL/TLS
#smtpd_tls_security_level = encrypt
# When TLS encryption is optional in the Postfix SMTP server, do not
# announce or accept SASL authentication over unencrypted connections.
#
smtpd_tls_auth_only = no
# A directory containing (PEM format) CA certificates of root CAs
# trusted to sign either remote SMTP client certificates or inter-
# mediate CA certificates.
#
# do not provide (not signing client certs)
#smtpd_tls_CApath =
# File with the Postfix SMTP server RSA certificate in PEM format.
#
smtpd_tls_cert_file = /etc/letsencrypt/live/smtp.geddy.au /fullchain.pem
# File with the Postfix SMTP server RSA private key in PEM format.
#
smtpd_tls_key_file = /etc/letsencrypt/live/smtp.geddy.au /privkey.pem
# Request that the Postfix SMTP server produces Received: message
# headers that include information about the protocol and cipher
# used, as well as the remote SMTP client CommonName and client
# certificate issuer CommonName.
#
smtpd_tls_received_header = yes
# Name of the file containing the optional Postfix SMTP server TLS
# session cache.
#
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
##::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
## NETWORK DELIVERY
##::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
## SMTP(8) - SMTP/LMTP CLIENT ::::::::::::::::::::::::::::::::::::::::
## STARTTLS
# The default SMTP TLS security level for the Postfix SMTP client;
# when a non-empty value is specified, this overrides the obsolete
# parameters smtp_use_tls, smtp_enforce_tls, and
# smtp_tls_enforce_peername.
#
# select one:
# STARTTLS
smtp_tls_security_level = may
# SSL/TLS
#smtp_tls_security_level = encyrpt
# Directory with PEM format Certification Authority certificates
# that the Postfix SMTP client uses to verify a remote SMTP server
# certificate.
#
smtp_tls_CApath = /etc/ssl/certs
# File with the Postfix SMTP client RSA certificate in PEM format.
#
# do not provide
#smtp_tls_cert_file =
# File with the Postfix SMTP client RSA private key in PEM format.
#
# do not provide
#smtp_tls_key_file =
# The external entropy source for the in-memory tlsmgr(8) pseudo
# random number generator (PRNG) pool.
#
#tls_random_source = dev:/dev/urandom
## Resource and Rate Controls
# The time unit over which client connection rates and other rates are
# calculated.
#
anvil_rate_time_unit = 60s
# The maximal number of recipients that the Postfix SMTP server
# accepts per message delivery request.
#
smtpd_recipient_limit = 250
# How many simultaneous connections any client is allowed to make
# to this service.
#
smtpd_client_connection_count_limit = 5
# The maximal number of connection attempts any client is allowed
# to make to this service per time unit.
#
smtpd_client_connection_rate_limit = 5
# The number of errors a remote SMTP client is allowed to make
# without delivering mail before the Postfix SMTP server slows
# down all its responses.
#
smtpd_soft_error_limit = 2
# The number of errors a remote SMTP client is allowed to make
# without delivering mail before the Postfix SMTP server slows
# down all its responses.
#
smtpd_hard_error_limit = 3
# the SMTP server response delay after a client has made more than
# $smtpd_soft_error_limit errors, and fewer than $smtpd_hard_error_limit
# errors, without delivering mail.
#
smtpd_error_sleep_time = 5s
# Wait until the RCPT TO command before evaluating
# $smtpd_client_restrictions, $smtpd_helo_restrictions and
# $smtpd_sender_restrictions, or wait until the ETRN command be‐
# fore evaluating $smtpd_client_restrictions and $smtpd_helo_re‐
# strictions.
#
smtpd_delay_reject = yes
# Require that a remote SMTP client introduces itself with the
# HELO or EHLO command before sending the MAIL command or other
# commands that require EHLO negotiation.
#
smtpd_helo_required = yes
# Optional restrictions that the Postfix SMTP server applies in
# the context of a client connection request.
#
smtpd_client_restrictions =
permit_mynetworks
permit_sasl_authenticated
reject_unknown_client_hostname
reject_unauth_pipelining
# reject_rbl_client zen.spamhaus.org
# ^ recommended use RBL in spamassassin not MTA
# Optional restrictions that the Postfix SMTP server applies in
# the context of a client HELO command.
#
smtpd_helo_restrictions =
reject_non_fqdn_hostname
reject_invalid_helo_hostname
# reject_unknown_helo_hostname
# ^ rejects internal domain before chance to SASL so disable
# Optional restrictions that the Postfix SMTP server applies in
# the context of a client MAIL FROM command.
#
smtpd_sender_restrictions =
permit_mynetworks
reject_non_fqdn_sender
reject_unknown_sender_domain
# Optional restrictions that the Postfix SMTP server applies in
# the context of a client RCPT TO command, after smtpd_relay_re‐
# strictions.
#
smtpd_recipient_restrictions =
permit_mynetworks
reject_unauth_pipelining
permit_sasl_authenticated
reject_invalid_hostname
reject_non_fqdn_hostname
reject_non_fqdn_sender
reject_non_fqdn_recipient
reject_unauth_destination
# reject_rbl_client zen.spamhaus.org
# reject_rbl_client dul.dnsbl.sorbs.net
# ^ recommended use RBL in spamassassin not MTA
# Access restrictions for mail relay control that the Postfix SMTP
# server applies in the context of the RCPT TO command, before
# smtpd_recipient_restrictions.
#
smtpd_relay_restrictions =
permit_mynetworks
permit_sasl_authenticated
defer_unauth_destination
## VIRTUAL(8) - VIRTUAL DOMAIN DELIVERY AGENT ::::::::::::::::::::::::
## Mailbox Delivery
# Optional lookup tables that alias specific mail addresses or domains
# to other local or remote address.
#
virtual_alias_maps =
hash:/etc/postfix/virtual/geddy.au
# Postfix is final destination for the specified list of domains;
# mail is delivered via the $virtual_transport mail delivery
# transport.
#
virtual_mailbox_domains = /etc/postfix/vdomain
# Optional lookup tables with all valid addresses in the domains
# that match $virtual_mailbox_domains.
#
virtual_mailbox_maps =
hash:/etc/postfix/vmailbox/geddy.au
# A prefix that the virtual(8) delivery agent prepends to all
# pathname results from $virtual_mailbox_maps table lookups.
#
virtual_mailbox_base = /var/mail/vhosts
# The minimum user ID value that the virtual(8) delivery agent
# accepts as a result from $virtual_uid_maps table lookup.
#
virtual_minimum_uid = 100
# Lookup tables with the per-recipient user ID that the virtual(8)
# delivery agent uses while writing to the recipient's mailbox.
#
virtual_uid_maps = static:5000
# Lookup tables with the per-recipient group ID for virtual(8)
# mailbox delivery.
#
virtual_gid_maps = static:5000
# The default mail delivery transport and next-hop destination for
# final delivery to domains listed with $virtual_mailbox_domains.
#
#virtual_transport = virtual
# call Dovecot's delivery (virtual) for each recipient instead of only
# one time for all recipients.
#
dovecot_destination_recipient_limit = 1
graham:~ sudo vi /etc/aliases
/etc/aliases
replace all content
# formulate delivery address for (apparent) local user
# important local mail roles
postmaster: root
admin: root
nobody: /dev/null
# local account re-redirects
root: root+s1@geddy.au
graham:~ sudo newaliases
graham:~ sudo addgroup --gid 5000 vmail # group of virtual users' email
graham:~ sudo adduser --uid 5000 --ingroup vmail --no-create-home --home /var/mail \
--gecos 'virtual mail users' --shell /usr/sbin/nologin vmail # proxy of virtual users' email
graham:~ sudo usermod --expiredate 1 vmail
User vmail:vmail
exists to own the virtual user mail content.
Ensure this account is disabled from login.
graham:~ sudo adduser postfix vmail
graham:~ sudo mkdir /var/mail/vhosts # container for per-domain email volumes
graham:~ sudo chmod 2770 /var/mail/vhosts
graham:~ sudo mkdir /var/mail/vhosts/geddy.au # container for this domain's email volume
graham:~ sudo chown -R vmail:vmail /var/mail/vhosts
graham:~ sudo mkdir /etc/postfix/vmailbox # container for per-domain mailboxes maps
graham:~ sudo vi /etc/postfix/vmailbox/geddy.au # this domain's mailboxes map
/etc/postfix/vmailbox/geddy.au
new file
# map virtual domain user to physical mailbox (geddy.au ).
# note: always use trailing '/' on mailbox file to ensure maildir format
fred.nerk @geddy.au geddy.au /fred.nerk /Maildir/
#OFF robot@geddy.au geddy.au /robot/Maildir
graham:~ sudo postmap /etc/postfix/vmailbox/geddy.au
graham:~ sudo mkdir /etc/postfix/virtual # container for per-domain forwarders maps
graham:~ sudo vi /etc/postfix/virtual/geddy.au # this domain's forwarders map
/etc/postfix/virtual/geddy.au
new file
# formulate delivery addresses for virtual domain (geddy.au )
# deal with domain root email if any
root@geddy.au fred.nerk @geddy.au
# important domain mail roles
postmaster@geddy.au root@geddy.au
webmaster@geddy.au root@geddy.au
admin@geddy.au root@geddy.au
abuse@geddy.au root@geddy.au
nobody@geddy.au nobody@localhost
robot@geddy.au nobody@geddy.au
# domain pseudo-account redirects
no-reply@geddy.au nobody@geddy.au
# domain distribution lists
# domain mail catch all - disabled to discourage spammer guesses
#OFF @geddy.au root@geddy.au
graham:~ sudo postmap /etc/postfix/virtual/geddy.au
graham:~ sudo vi /etc/postfix/vdomain # list of virtual domains supported
/etc/postfix/vdomain
new file
# list of virtual domains recognised
geddy.au
This is just a list so postmap
not required.
graham:~ sudo vi /etc/postfix/master.cf
/etc/postfix/main.cf
add highlighted line (previous line also shown)
smtp inet n - y - - smtpd
-o syslog_name=postfix/submission
… … uncomment lines
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
… … uncomment lines
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
… …
add highlighted line (previous line also shown)
# -o smtpd_recipient_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
… …
add highlighted lines (previous line also shown)
# -o milter_macro_daemon_name=ORIGINATING
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
… … append lines to end of file
dovecot unix - n n - - pipe
flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient}
spamassassin unix - n n - - pipe
user=debian-spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
graham:~ sudo certbot --standalone -d smtp.geddy.au # generate certificate
graham:~ sudo ufw allow 'Postfix SMTPS' # poke holes in firewall
graham:~ sudo ufw allow 'Postfix Submission'
Preferably do not open firewall to ports for unencrypted services
such as 'Postfix'
.
We cannot start postfix until dependencies upon dovecot
and spamassassin are satisfied.
dovecot
graham:~ sudo apt install dovecot-core dovecot-pop3d dovecot-impad dovecot-lmtpd dovecot-sieve
graham:~ sudo systemctl stop dovecot # stop dovecot for updating
The configuration of dovecot is spread across many files
under /etc/dovecot/conf.d/
.
graham:~ cd /etc/dovecot/conf.d
graham:/etc/dovecot/conf.d sudo vi 10-auth.conf
/etc/dovecot/conf.d/10-auth.conf
change settings
disable_plaintext_auth = no
auth_mechanisms = plain login
# !include auth-system.conf.ext
!include auth-passwdfile.conf.ext
graham:/etc/dovecot/conf.d sudo vi 10-mail.conf
/etc/dovecot/conf.d/10-mail.conf
change settings
mail_location = maildir:/var/mail/vhosts/%d/%n/Maildir
separator = /
# namespace virtual {
# type = private
# prefix = Virtual/
# separator = /
# location = maildir:/var/mail/vhosts/%d/%n/Maildir/virtual
# list = children
# }
namespace {
type = public
separator = /
prefix = Public/
location = maildir:/var/mail/vhosts/%d/public
subscriptions = yes
list = children
}
graham:/etc/dovecot/conf.d sudo vi 10-master.conf
/etc/dovecot/conf.d/10-master.conf
change settings
# unix_listener auth-userdb {
#mode = 0666
#user =
#group =
extra_groups = vmail
# }
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
user = postfix
group = vmail
mode = 0600
}
unix_listener auth-master {
user = vmail
group = vmail
mode = 0600
}
graham:/etc/dovecot/conf.d sudo vi 10-ssl.conf
/etc/dovecot/conf.d/10-ssl.conf
change settings
ssl = yes
ssl_cert = /etc/letsencrypt/live/imap.geddy.au /fullchain.pem
ssl_key = /etc/letsencrypt/live/imap.geddy.au /privkey.pem
ssl_client_ca_dir = /etc/ssl/certs
graham:/etc/dovecot/conf.d sudo vi 15-lda.conf
/etc/dovecot/conf.d/15-lda.conf
change settongs
protocol lda {
# Space separated list of plugins to load (default is global mail_plugins).
#mail_plugins = $mail_plugins
auth_socket_path = /var/run/dovecot/auth-master
hostname = imap.geddy.au
mail_plugin_dir = /usr/lib/dovecot/modules
mail_plugins = sieve
postmaster_address = postmaster
}
graham:/etc/dovecot/conf.d sudo vi auth-passwdfile.conf.ext
/etc/dovecot/conf.d/auth-passwdfile.conf.ext
change settings
passdb {
driver = passwd-file
args = /var/mail/vhosts/%d/shadow
}
userdb {
driver = passwd-file
args = /var/mail/vhosts/%d/passwd
# Default fields that can be overridden by passwd-file
#default_fields = quota_rule=*:storage=1G
# Override fields from passwd-file
#override_fields = home=/home/virtual/%u
}
graham:/etc/dovecot/conf.d cd
graham:~ sudo adduser dovecot vmail
graham:~ sudo certbot --standalone -d imap.geddy.au -d pop.geddy.au # generate certificate
graham:~ sudo ufw allow 'Dovecot Secure IMAP' # poke holes in firewall
graham:~ sudo ufw allow 'Dovecot Secure POP3'
Preferably do not open firewall to ports for unencrypted services
such as 'Dovecot IMAP'
and 'Dovecot POP3'
.
graham:~ sudo crontab -e # schedule 'taking out the trash'
…temp file …
new file or append to end
# purge Trash and Junk older than a month - monthly
# (-A option fails for sqlite backend, so workaround by iterating users)
#11 5 1 * * doveadm -v expunge -A mailbox Trash savedbefore 4w
11 5 1 * * for user in $(cut -f1 -d: /var/mail/vhosts/*/passwd) ; do doveadm -Dv expunge -u "$user" mailbox Trash savedbefore 4w ; done
#12 5 1 * * doveadm -v expunge -A mailbox Spam savedbefore 4w
12 5 1 * * for user in $(cut -f1 -d: /var/mail/vhosts/*/passwd) ; do doveadm -Dv expunge -u "$user" mailbox Spam savedbefore 4w ; done
spamassassin
graham:~ sudo apt install spamassassin
graham:~ sudo systemctl stop spamassassin # stop spamassassin for updating
graham:~ sudo vi /etc/default/spamassassin
/etc/default/spamassassin
change setting
CRON=1
graham:~ sudo vi /etc/spamassassin/local.cf
/etc/spamassassin/local.cf
change settings
rewrite_header Subject *****SPAM _SCORE_*****
report_safe 0
trusted_networks s0.geddy.au s1.geddy.au
#trusted_networks 142.250.0.0/15 # google
# lock_method flock
# required_score 5.0
# use_bayes 1
# bayes_auto_learn 1
shortcircuit ALL_TRUSTED on
… … append to end of file
# Turning on the skip_rbl_checks setting will disable the DNSEval plugin,
# which implements Real-time Block List (or: Blackhole List) (RBL) lookups.
# By default, SpamAssassin will run RBL checks. Individual blocklists may
# be disabled selectively by setting a score of a corresponding rule to 0.
#
# skip_rbl_checks 0
# Turning on the skip_uribl_checks setting will disable the URIDNSBL plugin.
# By default, SpamAssassin will run URI DNSBL checks. Individual URI
# blocklists may be disabled selectively by setting a score of a corresponding
# rule to 0 or through the uridnsbl_skip_domain parameter. Turning on the
# skip_uribl_checks setting will disable the URIDNSBL plugin.
#
# skip_urirbl_checks 0
graham:~ sudo vi /etc/spamassassin/65_debian.cf
/etc/spamassassin/65_debian.cf
comment out last line
# score RCVD_IN_BRBL_LASTEXT 0
This enables barracuda blacklist, but…
You must register (free! it just helps stop their free service being abused
on open internet). It takes a few minutes and you must specify to them
your server's IP address.
Browse to https://barracudacentral.org
;
Select BRBL > Account ;
Enter your details; and
Provide the IP addresses of both s0.geddy.au
and s1.geddy.au
.
Once registration confirmed, move on to the test below.
graham:~ host 2.0.0.127.b.barracudacentral.org
2.0.0.127.b.barracudacentral.org has address 127.0.0.2
Verify address reported is 127.0.0.2
,
indicating barracuda account is working.
Start them all
graham:~ sudo systemctl start postfix dovecot spamassassin
graham:~ sudo systemctl status postfix dovecot spamassassin
graham:~ sudo tail -f /var/log/mail.log
Verify the services have started cleanly.
graham:~ sudo postsuper -d ALL # purge outgoing mail queue
graham:~ mailx -s test root < /dev/null
graham:~ mailq
graham:~ sudo tail -f /var/log/mail.log
Verify the test mail was routed from local root
to the
virtual address designated for it in /etc/aliases
(presumably an imap account we have created).
Appendix: Client configuration
For our example virtual user:
user
fred.nerk @geddy.au
password
****(as assigned)****
incoming
imap.geddy.au :993 SSL/TLS
outgoing
smtp.geddy.au :465 SSL/TLS
Appendix: Script to add virtual user
graham:~ sudo vi /usr/local/sbin/add-virtual-user
/use/local/sbin/add-virtual-user
new file
#!/bin/bash
# add-virtual-user: add user to postfix and dovecot virtual domain
# (c)2021 Graham Eddy ; provided under GPLv3 license
# run as superuser
#
# originated from script on https://tech.tiq.cc/2014/02/how-to-set-up-an-\
#vemail-server-with-postfix-and-dovecot-without-mysql-on-debian-7/
abort() {
[ $# -gt 0 ] && echo "$@" 1>&2
exit 2
}
usage() {
echo "usage: $0 virtuser password [basedir]" 1>& 2
abort $@
}
# check privileges
[ "$EUID" == 0 ] || abort "$0: not superuser"
# process command line args
case $# in
2 | 3 )
virtuser="$1"
{ echo "$virtuser" | grep '@' > /dev/null ; } || abort "$virtuser: no @ in virtuser"
username=$(echo "$virtuser" | cut -f1 -d'@')
domain=$(echo "$virtuser" | cut -f2 -d'@')
[ "$username" ] || abort "$virtuser: missing username"
[ "$domain" ] || abort "$virtuser: missing domain"
passwd="$2"
basedir="${3:-$(postconf | grep '^virtual_mailbox_base ' | cut -f3 -d' ')}"
;;
* ) usage ;;
esac
grep "$domain" /etc/postfix/vdomain > /dev/null || abort "$domain: domain not defined"
########################################################################
# postfix
# container for domains
mkdir -p /etc/postfix/vmailbox || abort
chown root:root /etc/postfix/vmailbox || abort
chmod 755 /etc/postfix/vmailbox || abort
# this domain
vmailbox_file="/etc/postfix/vmailbox/$domain"
[ -f "$vmailbox_file" ] || touch "$vmailbox_file"
chown root:root "$vmailbox_file" || abort
chmod 644 "$vmailbox_file" || abort
# this user
if grep "^$virtuser " "$vmailbox_file" > /dev/null ; then
tty -s && echo "$virtuser: virtuser already known to Postfix, skipped add"
else
# force maildir format by using trailing '/'
echo "$virtuser $domain/$username/Maildir/" >> "$vmailbox_file" || abort
postmap "$vmailbox_file" || abort
fi
# no need to restart postfix
########################################################################
# dovecot
dovecot_changed=
# container for domains
mkdir -p "$basedir" || abort
chown vmail:vmail "$basedir" || abort
chmod 2750 "$basedir" || abort
# this domain
mkdir -p "$basedir/$domain" || abort
chown vmail:vmail "$basedir/$domain" || abort
chmod 2755 "$basedir/$domain" || abort
# user database for this domain
passwd_file="$basedir/$domain/passwd"
[ -f "$passwd_file" ] || touch "$passwd_file" || abort
chown root:dovecot "$passwd_file" || abort
chmod 644 "$passwd_file" || abort
# add this user
if grep "^$virtuser:" "$passwd_file" > /dev/null ; then
tty -s && echo "$virtuser: virtuser already known to Dovecot/passwd, skipped add"
else
echo "$virtuser::5000:5000::$basedir/$domain/$username" >> "$passwd_file" || abort
dovecot_changed=yes
fi
# password database for this domain
shadow_file="$basedir/$domain/shadow"
[ -f "$shadow_file" ] || touch "$shadow_file" || abort
chown root:dovecot "$shadow_file" || abort
chmod 640 "$shadow_file" || abort
# add this user's password (uses `doveadm pw` to encrypt password)
if grep "^$virtuser:" "$shadow_file" > /dev/null ; then
tty -s && echo "$virtuser: virtuser already known to Dovecot/shadow, skipped add"
else
echo "$virtuser:$(doveadm pw -p $passwd)" >> "$shadow_file" || abort
dovecot_changed=yes
fi
# restart dovecot if config changed
[ "$dovecot_changed" ] && systemctl reload dovecot
graham:~ sudo chmod 554 /usr/local/sbin/add-virtual-user