Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
644 lines (482 sloc) 15.4 KB
: qmail extras
A collection of additional useful things for running netqmail + dovecot + roundcube + ezmlm-idx.
Main guide here: [0]
<!--TOC-->
:: Global footers in Roundcube
This will put footers to all mails sent in Roundcube for all users:
====
vhost_dir="/var/www/vhosts/${mail_domain}/htdocs"
mkdir ${vhost_dir}/footers
# e.g.:
echo '
Jugend Rettet e.V.
Postfach: 360355
D- 10997 Berlin
Website: www.jugendrettet.org
Spenden: www.jugendrettet.org/spenden
Betterplace: www.jugendrettet.org/betterplace
Facebook: www.facebook.com/JugendRettet
Twitter: www.twitter.com/jugendrettet
Instagram: www.instagram.com/jugendrettet/
' > ${vhost_dir}/footers/jr.txt
echo '
<p>Jugend Rettet e.V.<br>
Postfach: 360355<br>
D- 10997 Berlin</p>
<p>Website: <a href="https://www.jugendrettet.org">www.jugendrettet.org</a><br>
Spenden: <a href="https://www.jugendrettet.org/spenden">www.jugendrettet.org/spenden</a><br>
Betterplace: <a href="https://www.jugendrettet.org/betterplace">www.jugendrettet.org/betterplace</a><br>
Facebook: <a href="https://www.facebook.com/JugendRettet">www.facebook.com/JugendRettet</a><br>
Twitter: <a href="https://www.twitter.com/jugendrettet">www.twitter.com/jugendrettet</a><br>
Instagram: <a href="https://www.instagram.com/jugendrettet/">www.instagram.com/jugendrettet/</a></p>
<img src="https://jugendrettet.org/graphics/logo_s.png">
' > ${vhost_dir}/footers/jr.html
cd /etc/roundcubemail
cp defaults.inc.php defaults.inc.php.orig
sed -i -e "s/^\$config\['generic_message_footer/#\$config\['generic_message_footer/g" defaults.inc.php
echo "
\$config['generic_message_footer'] = 'footers/jr.txt';
\$config['generic_message_footer_html'] = 'footers/jr.html';
" >> defaults.inc.php
====
:: Open the preview pane by default
====
cd /etc/roundcubemail
sed -i -e "s/^\$config\['preview_pane/#\$config\['preview_pane/g" defaults.inc.php
echo "
\$config['preview_pane'] = true;
" >> defaults.inc.php
====
:: very simple monitoring
This will only cover the services under daemontools and simply check whether every service is running longer than n seconds. Otherwise someone gets a mail:
====
cat > $HOME/src/daemontools-monitor.sh << __EOF__
#!/bin/sh
seconds='10'
rcpt='postmaster'
re='^[0-9]+$'
stats="\$(/usr/local/bin/svstat /service/*)"
echo "\${stats}" | awk '{print \$5}' \
| while read s; do
if [[ \${seconds} -gt \${s} ]] || ! [[ \${s} =~ \${re} ]]; then
echo "\${stats}" | mail -s 'daemontools monitor' \${rcpt}
exit 1
fi
done
__EOF__
====
Add to crontab to run every ten minutes:
====
chmod +x daemontools-monitor.sh
(crontab -l 2>/dev/null; echo "*/10 * * * * $HOME/src/daemontools-monitor.sh") | crontab -
====
This will send a mail when root logs in:
====
cat >> /root/.bashrc << _EOF_
login_info="\$(who | head -n1 | cut -d'(' -f2 | cut -d')' -f1)"
message="\$(
printf "ALERT - Root Shell Access (%s) on:\n" "\$(hostname)"
date
echo
who
)"
mail -s "Alert: Root Access from \${login_info}" admin <<< "\${message}"
_EOF_
====
:: Change domain name
Check list:
* On DO: Change name of Droplet for reverse DNS.
* Preparation
* Change domain for OS itself.
* Get new certificates.
* Configure qmail for it.
* Configure Roundcube for it.
* Change virtual hosts for the web server.
::: Preparation
We assume that only the main part changes, e.g. EXAMPLE.URL.
====
new_address='FOO'
. $HOME/.domain-vars.txt
old_address="${address}"
old_domain="${domain}"
sed -i -e "s/${old_address}/${new_address}/g" $HOME/.domain-vars.txt
. $HOME/.domain-vars.txt
====
::: Change domain for OS itself
====
file='/etc/sysconfig/network'
sed -i -e 's/^HOSTNAME/#HOSTNAME/' $file
echo "HOSTNAME=${domain}" >> $file
ip="$(ifconfig eth0 | grep 'inet addr' | cut -d: -f2 | awk '{print $1}')"
sed -i -e "s/^${ip}/#${ip}/" /etc/hosts
printf "${ip}\t%s\n" "${domain}" >> /etc/hosts
hostname ${domain}
hostname --fqdn
====
::: Get new certificates.
/Use the second line to agree to their TOS without user input./
====
svc -d /service/lighttpd/
cd $HOME/src/letsencrypt/
./certbot-auto -n --email admin@${address} certonly --standalone -d ${domain} \
-d ${address} -d imap.${address} -d smtp.${address}
# ./certbot-auto -n --email admin@${address} --agree-tos certonly --standalone \
-d ${domain} -d ${address} -d imap.${address} -d smtp.${address}
mksh $HOME/src/letsencrypt/renew.sh
====
::: Configure qmail for it
====
cd /usr/local/src/netqmail-1.06
# Do these, if the old domain shouldn't be supported at all from now on:
# > /var/qmail/control/locals; > /var/qmail/control/rcpthosts
./config-fast ${address}
qmailctl restart
====
::: Configure Roundcube for it
====
sed -i -e "s/${old_address}/${address}/g" /etc/roundcubemail/config.inc.php
svc -du /service/lighttpd
====
Also change the identities for existing users:
====
echo "USE roundcubemail
UPDATE identities
SET email = REPLACE(email, '${old_address}', '${address}')
WHERE email LIKE '%@${old_address}%'
" | mysql -u root -p"${mysql_root_password}" roundcubemail
====
::: Change virtual hosts for the web server
====
cd /var/www/vhosts/
mv "${old_domain}" "${domain}"
====
:: Deny access to Roundcube's sensible directories
This is not necessary in context of this guide, as we don't put these directories in any web readable place anyway. But these lines already exist and maybe they come in handy for someone:
====
roundcube_dir="/var/www/vhosts/${mail_domain}/htdocs"
cat > /etc/lighttpd/conf.d/roundcube-deny.conf <<__EOF__
\$HTTP["host"] =~ "${mail_domain}\$"{
\$HTTP["url"] =~ "^/config" {
url.access-deny = ("")
}
\$HTTP["url"] =~ "^/temp" {
url.access-deny = ("")
}
\$HTTP["url"] =~ "^/logs" {
url.access-deny = ("")
}
}
__EOF__
echo 'include "conf.d/roundcube-deny.conf"' >> /etc/lighttpd/lighttpd.conf
svc -du /service/lighttpd
====
:: passwd as fallback userdb for dovecot
With checkpassword / checkvpw we are getting all the information dovecot needs for everyday operation in one action when doing the passdb lookup.
For some things, e.g. migration with dsync (see below), dovecot needs more information. We can use the backend passwd, because our users are actual unix users. We put the configuration for it below the one for checkkpassword / checkvpw, so that dovecot will use this method when lookup with checkkpassword / checkvpw fails.
====
echo '
userdb {
driver = passwd
override_fields = mail=maildir:/home/%u/Maildir
}' >> /usr/local/etc/dovecot/conf.d/auth-checkvpw.conf.ext
svc -du /service/dovecot
====
:: Migrate from other mail servers
Add configuration:
====
remote_imap_host='FOO.BAR'
cd /usr/local/etc/dovecot/
echo "
imapc_host = ${remote_imap_host}
# Authenticate as masteruser / masteruser-secret, but use a separate login user.
# If you don't have a master user, remove the imapc_master_user setting.
# imapc_user = %u
# imapc_master_user = masteruser
# imapc_password = masteruser-secret
imapc_features = rfc822.size
# If you have Dovecot v2.2.8+ you may get a significant performance improvement with fetch-headers:
imapc_features = $imapc_features fetch-headers
# Read multiple mails in parallel, improves performance
mail_prefetch_count = 20
# If the old IMAP server uses INBOX. namespace prefix, set:
imapc_list_prefix = INBOX
# for SSL:
imapc_port = 993
imapc_ssl = imaps
# Next line applies to at least CentOS 6:
ssl_client_ca_file = /etc/ssl/certs/ca-bundle.trust.crt
imapc_ssl_verify = yes
" > conf.d/migrate-dsync.conf.ext
echo '!include conf.d/migrate-dsync.conf.ext' >> local.conf
svc -du /service/dovecot
====
This would be the command for syncing one user:
====
local_user='FOO'
remote_imap_user="${local_user}@BAR"
remote_imap_passwd='XYZ'
doveadm -o imapc_user=${remote_imap_user} -o imapc_password=${remote_imap_passwd} backup -R -u ${local_user} imapc:
====
But here we will use a script that reads a file with pairs of users and passwords of the remote host we are migrating from. Then it will:
* create the user with the password on our machine
* (optionally it will create new passwords for each user, dumping a new file with new pairs of users and their passwords to pass them to them)
* execute the above command for each user until everyone is synced
* if a user already existed locally, it tries to one-way sync from remote
====
cd $HOME/src/
cat > dsync-migrate.sh <<__EOF__
#!/bin/sh
# The address is read from \$1.
# The list of user-password pairs is read from ./upw-lists/\${address}/remote.txt
# If the directory doesn't exist, it will be created at first run.
set -eu
create_new_pairs="1"
address="\$1"
user_pw_list_dir="./upw-lists/\${address}"
remote_user_pw_list_file="\${user_pw_list_dir}/remote.txt"
date_unix_time="\$(date +%Y%m%d-%s)"
new_user_pw_list_file="\${user_pw_list_dir}/new_\${date_unix_time}.txt"
function checkcontent() {
awk -v FS=' ' 'NR=="'\$line'"{print \$"'\$field'";}' \${remote_user_pw_list_file}
}
function get_pairs() {
field="1"
local_user="\$(checkcontent)"
remote_imap_user="\${local_user}@\${address}"
field="2"
remote_imap_passwd="\$(checkcontent)"
passwd="\${remote_imap_passwd}"
}
function check_existence() {
if id "\${local_user}" >/dev/null 2>&1; then
user_exists="1"
else
user_exists="0"
fi
}
function create_new_pairs() {
printf '%s' "\${local_user}" >> \${new_user_pw_list_file}
if [[ "\${user_exists}" -eq "0" ]]; then
passwd="\$(</dev/urandom tr -dc A-Za-z0-9 | head -c20)"
else
passwd='USER_EXISTED'
fi
printf ' %s\n' "\${passwd}" >> \${new_user_pw_list_file}
}
function create_user() {
new_user="\${local_user}"
new_passwd="\${passwd}"
useradd \${new_user}
echo "\${new_user}:\${new_passwd}" | chpasswd
}
function sync() {
if [[ "\${user_exists}" -eq "0" ]]; then
mv -f /home/\${local_user}/Maildir \\
/home/\${local_user}/Maildir.dsyncb-\${date_unix_time}
su - \${local_user} -c "doveadm -o mail_fsync=never \\
-o imapc_user=\${remote_imap_user} \\
-o imapc_password=\${remote_imap_passwd} backup -R -u \${local_user} imapc:"
else
su - \${local_user} -c "doveadm -o mail_fsync=never \\
-o imapc_user=\${remote_imap_user} \\
-o imapc_password=\${remote_imap_passwd} sync -1 -R -u \${local_user} imapc:"
fi
}
if [ ! -d "\${user_pw_list_dir}" ]; then
mkdir -pv "\${user_pw_list_dir}"
echo "Now put the remote user-password list to \${user_pw_list_dir}/remote.txt".
exit 1
fi
line="1"
line_count="\$(wc -l \${remote_user_pw_list_file} | cut -d ' ' -f 1)"
until [[ "\${line}" -gt "\${line_count}" ]]; do
get_pairs
check_existence
if [[ "\${create_new_pairs}" -eq "1" ]]; then
create_new_pairs
fi
if [[ "\${user_exists}" -eq "0" ]]; then
create_user
fi
sync
line=\$(( \${line} + 1 ))
done
__EOF__
====
When done, you can remove the necessary config part:
====
sed -i \
-e 's/!include\ conf\.d\/migrate-dsync\.conf\.ext/#!include\ conf\.d\/migrate-dsync\.conf\.ext/' \
/usr/local/etc/dovecot/local.conf
svc -du /service/dovecot
====
:: Roundcube: reply to list if ML is detected
====
cat >> /etc/roundcubemail/config.inc.php << __EOF__
// Default behavior of Reply-All button:
// 0 - Reply-All always
// 1 - Reply-List if mailing list is detected
\$config['reply_all_mode'] = 1;
__EOF__
====
:: additional ports for SSHD
This might be necessary when outgoing port 22 is blocked.
Sometimes besides 80 and 443 ports for mail related tasks are open too.
Out of them we are not using 110 and 995 anyway:
====
echo '
Port 22
Port 110
Port 995
' >> /etc/ssh/sshd_config
service sshd restart
====
:: fail2ban
====
yum -y install fail2ban
chkconfig fail2ban on
service fail2ban start
====
::: SSHD
====
echo '[sshd]
enabled = true
[sshd-ddos]
enabled = true' > /etc/fail2ban/jail.d/sshd.conf
====
::: dovecot
====
echo '[dovecot]
enabled = true' > /etc/fail2ban/jail.d/dovecot.conf
====
Restart.
====
service fail2ban restart
====
:: iptables
This will be very basic.
After you set up your tables, store them:
====
iptables-save | sudo tee /etc/sysconfig/iptables
====
A script for setting up very basic rules can be found here [1].
:: tlsdate
To sync the system clock.
====
yum -y install git automake libevent2 libevent2-devel
====
====
cd $HOME/src
git clone https://github.com/ioerror/tlsdate.git
cd tlsdate
useradd -r -g nofiles tlsdate
./autogen.sh
./configure --with-unpriv-group=nofiles --with-unpriv-user=tlsdate
make && make install
====
====
mkdir -m 0755 -p /var/service/tlsdated/log
mkdir -m 0750 /var/log/tlsdated
chown tlsdate /var/log/tlsdated
echo '#!/bin/sh
cmd="/usr/local/sbin/tlsdated"
exec ${cmd} 2>&1
' > /var/service/tlsdated/run
echo '#!/bin/sh
exec /usr/local/bin/setuidgid tlsdate /usr/local/bin/multilog t /var/log/tlsdated
' > /var/service/tlsdated/log/run
chmod -R 0755 /var/service/tlsdated
chmod +x /var/service/tlsdated/run /var/service/tlsdated/log/run
ln -s /var/service/tlsdated /service/
====
:: autoresponder
We will use qmail-autoresponder by Bruce Guenter (untroubled.org).
First we need his bglibs as a dependency (and glibc-static for itself).
Unfortunately, will also need MySQL headers even if we won't be using qmail-autoresponder-mysql. The Makefile just isn't working as described.
We won't use the newest versions of qmail-autoresponder bglibs because they are not compatible with GCC 4.4.
====
yum -y install glibc-static
cd $HOME/src/
wget http://untroubled.org/bglibs/archive/bglibs-1.106.tar.gz \
http://untroubled.org/bglibs/archive/bglibs-1.106.tar.gz.sig
gpg2 --recv-key C14D3C67
gpg2 --verify bglibs-1.106.tar.gz.sig bglibs-1.106.tar.gz
====
OK?
====
tar -xf bglibs-1.106.tar.gz
cd bglibs-1.106
make
make install
====
Now qmail-autoresponder:
====
yum -y install mysql-devel
cd $HOME/src/
wget http://untroubled.org/qmail-autoresponder/archive/qmail-autoresponder-0.97.tar.gz \
http://untroubled.org/qmail-autoresponder/archive/qmail-autoresponder-0.97.tar.gz.sig
gpg2 --verify gpg2 --verify qmail-autoresponder-0.97.tar.gz.sig \
qmail-autoresponder-0.97.tar.gz
====
OK?
====
tar -xf qmail-autoresponder-0.97.tar.gz
cd qmail-autoresponder-0.97
make
make install
====
::: creating an autorespond
* create a directory for the corresponding user
* put the message including headers inside 'message.txt' in the directory
* make the directory 0700 and the user the owner
* create a .qmail piping mails and place of the directory to qmail-autorespond
* make the user the owner
====
. $HOME/.domain-vars.txt
user='john'
message="Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 8bit
From: ${user}@${address}
Subject: Autoresponse: I'm away
Hi,
some body text.
Best regards.
"
cd $(su - ${user} -c 'echo $HOME')
mkdir autoresponse
echo "${message}" > autoresponse/message.txt
chown -R ${user}:${user} autoresponse
chmod -R 0700 autoresponse
cp .qmail dotqmail.b
echo '# |/usr/local/bin/ifspamh postmaster-spam # better use some anti spam
|qmail-autoresponder ~/autoresponse/
./Maildir/' > dotqmail
chown -R ${user}:${user} dotqmail
chmod 0640 dotqmail
mv dotqmail .qmail
====
:: Logging last logins in dovecot
====
mkdir /var/dovecot
touch /var/dovecot/lib.txt
chown -R dovenull:dovenull /var/dovecot/
chmod 770 /var/dovecot/
chmod 660 /var/dovecot/lib.txt
echo '
#### last login dict
mail_access_groups = dovenull
protocol imap {
mail_plugins = $mail_plugins last_login
}
protocol pop3 {
mail_plugins = $mail_plugins last_login
}
plugin {
last_login_dict = file:/var/dovecot/lib.txt
#last_login_key = last-login/%u # default
}
' >> /usr/local/etc/dovecot/local.conf
svc -du /service/dovecot/
====
[0] /hosting/mail/qmail-dovecot-roundcube.html
[1] https://gist.github.com/alexh-name/d99f665bfc7dd6b35998523d63caa873