lots o fixes, beets, shellcheck stuff
[distro-setup] / mail-setup
index 0ec838413a7f00e806e6f7fbb49fbc7d9e5b5252..30c987f457ec1bfb895071300276f2614420b0cf 100755 (executable)
@@ -3,6 +3,15 @@
 # Copyright (C) 2019 Ian Kelling
 # SPDX-License-Identifier: AGPL-3.0-or-later
 
+
+# shellcheck disable=SC2254 # makes for a lot of unneeded quotes
+
+
+# perusing through /el/mainlog without test messages:
+# &!testignore|jtuttle|
+#
+#&! testignore|jtuttle|eximbackup|/usr/sbin/exim4 -bpu
+
 # todo: check new macro DKIM_TIMESTAMPS
 
 # todo: check if REMOTE_SMTP_INTERFACE or REMOTE_SMTP_TRANSPORTS_HEADERS_REMOVE can simplify my or fsfs config
@@ -292,7 +301,7 @@ reload=false
 if [[ -e /var/local/mail-setup-reload ]]; then
   reload=true
 fi
-i() { # install file
+u() { # update file. note: duplicated in brc
   local tmp tmpdir dest="$1"
   local base="${dest##*/}"
   local dir="${dest%/*}"
@@ -300,13 +309,13 @@ i() { # install file
     # dest has a directory component
     mkdir -p "$dir"
   fi
-  ir=false # i result
+  ur=false # u result
   tmpdir=$(mktemp -d)
   cat >$tmpdir/"$base"
   tmp=$(rsync -ic $tmpdir/"$base" "$dest")
   if [[ $tmp ]]; then
     printf "%s\n" "$tmp"
-    ir=true
+    ur=true
     if [[ $dest == /etc/systemd/system/* ]]; then
       touch /var/local/mail-setup-reload
       reload=true
@@ -328,9 +337,19 @@ soff () {
   done
 }
 sre() {
+  local enabled
   for service; do
     m systemctl restart $service
-    m systemctl enable $service;
+    # Optimization for exim,
+    # is-enabled: 0m0.015s
+    # enable: 0m0.748s
+    # It is related to this message:
+    # exim4.service is not a native service, redirecting to systemd-sysv-install.
+    # Executing: /lib/systemd/systemd-sysv-install enable exim4
+    enabled=$(systemctl is-enabled $service 2>/dev/null ||:)
+    if [[ $enabled != enabled ]]; then
+      m systemctl enable $service
+    fi
   done
 }
 mailhost() {
@@ -432,7 +451,7 @@ fi
 
 # * Mail clean cronjob
 
-i /etc/systemd/system/mailclean.timer <<'EOF'
+u /etc/systemd/system/mailclean.timer <<'EOF'
 [Unit]
 Description=Run mailclean daily
 
@@ -443,7 +462,7 @@ OnCalendar=monthly
 WantedBy=timers.target
 EOF
 
-i /etc/systemd/system/mailclean.service <<EOF
+u /etc/systemd/system/mailclean.service <<EOF
 [Unit]
 Description=Delete and archive old mail files
 After=multi-user.target
@@ -457,7 +476,7 @@ EOF
 # * postgrey
 
 
-i /etc/default/postgrey <<'EOF'
+u /etc/default/postgrey <<'EOF'
 POSTGREY_OPTS="--exim --unix=/var/run/postgrey/postgrey.sock --retry-window=4 --max-age=60"
 EOF
 
@@ -465,7 +484,7 @@ EOF
 
 m usermod -a -G Debian-exim clamav
 
-i /etc/systemd/system/clamav-daemon.service.d/fix.conf <<EOF
+u /etc/systemd/system/clamav-daemon.service.d/fix.conf <<EOF
 [Service]
 ExecStartPre=-/bin/mkdir -p /var/run/clamav
 ExecStartPre=/bin/chown clamav /var/run/clamav
@@ -538,7 +557,7 @@ esac
 case $HOSTNAME in
   li) : ;;
   *)
-    i /etc/systemd/system/wg-quick@wgmail.service.d/override.conf <<EOF
+    u /etc/systemd/system/wg-quick@wgmail.service.d/override.conf <<EOF
 [Unit]
 Requires=mailnn.service
 JoinsNamespaceOf=mailnn.service
@@ -558,7 +577,7 @@ esac
 
 
 # https://selivan.github.io/2017/12/30/systemd-serice-always-restart.html
-i /etc/systemd/system/mailvpn.service <<EOF
+u /etc/systemd/system/mailvpn.service <<EOF
 [Unit]
 Description=OpenVPN tunnel for mail
 After=syslog.target network-online.target mailnn.service
@@ -602,7 +621,7 @@ RestartSec=20
 WantedBy=multi-user.target
 EOF
 
-i /etc/systemd/system/mailnnroute.service <<'EOF'
+u /etc/systemd/system/mailnnroute.service <<'EOF'
 [Unit]
 Description=Network routing for mailnn
 After=syslog.target network-online.target mailnn.service
@@ -626,7 +645,7 @@ WantedBy=multi-user.target
 EOF
 
 #
-i /etc/systemd/system/mailnn.service <<'EOF'
+u /etc/systemd/system/mailnn.service <<'EOF'
 [Unit]
 Description=Network Namespace for mail vpn service that will live forever and cant fail
 After=syslog.target network-online.target
@@ -641,7 +660,7 @@ ExecStart=/bin/sleep infinity
 WantedBy=multi-user.target
 EOF
 
-i /etc/systemd/system/mailbindwatchdog.service <<EOF
+u /etc/systemd/system/mailbindwatchdog.service <<EOF
 [Unit]
 Description=Watchdog to restart services relying on systemd-resolved dir
 After=syslog.target network-online.target
@@ -675,18 +694,18 @@ rm -fv /etc/systemd/system/openvpn-client-mail@.service
 # If we ever notice this change, chattr +i on it
 # trust-ad is used in t10+, glibc 2.31
 
-i /etc/127.0.0.1-resolv/stub-resolv.conf <<'EOF'
+u /etc/127.0.0.1-resolv/stub-resolv.conf <<'EOF'
 nameserver 127.0.0.1
 options edns0 trust-ad
 EOF
 
-i /etc/127.0.0.53-resolv/stub-resolv.conf <<'EOF'
+u /etc/127.0.0.53-resolv/stub-resolv.conf <<'EOF'
 nameserver 127.0.0.53
 options edns0 trust-ad
 EOF
 
 
-i /etc/10.173.8.1-resolv/stub-resolv.conf <<'EOF'
+u /etc/10.173.8.1-resolv/stub-resolv.conf <<'EOF'
 nameserver 10.173.8.1
 options edns0 trust-ad
 EOF
@@ -717,7 +736,7 @@ fi
 case $HOSTNAME in
   $MAIL_HOST)
     # todo, should this be after vpn service
-    i /etc/systemd/system/unbound.service.d/nn.conf <<EOF
+    u /etc/systemd/system/unbound.service.d/nn.conf <<EOF
 [Unit]
 After=mailnn.service
 JoinsNamespaceOf=mailnn.service
@@ -766,7 +785,7 @@ EOF
     ;;&
   $MAIL_HOST|bk)
     for unit in ${nn_progs[@]}; do
-      i /etc/systemd/system/$unit.service.d/nn.conf <<EOF
+      u /etc/systemd/system/$unit.service.d/nn.conf <<EOF
 [Unit]
 
 # Wants appears better than requires because with requires,
@@ -804,7 +823,7 @@ esac
 # * wghole (another mail vpn)
 
 if $bhost_t; then
-  i /etc/systemd/system/wg-quick@wghole.service.d/override.conf <<'EOF'
+  u /etc/systemd/system/wg-quick@wghole.service.d/override.conf <<'EOF'
 [Unit]
 StartLimitIntervalSec=0
 
@@ -815,15 +834,15 @@ EOF
 fi
 
 # * spamassassin config
-i /etc/sysctl.d/80-iank-mail.conf <<'EOF'
+u /etc/sysctl.d/80-iank-mail.conf <<'EOF'
 # see exim spec
 net.netfilter.nf_conntrack_tcp_timeout_close_wait = 120
 EOF
-if $ir; then
+if $ur; then
   m sysctl -p
 fi
 
-i /etc/spamassassin/mylocal.cf <<'EOF'
+u /etc/spamassassin/mylocal.cf <<'EOF'
 # this is mylocal.cf because the normal local.cf has a bunch of upstream stuff i dont want to mess with
 
 # /usr/share/doc/exim4-base/README.Debian.gz:
@@ -842,7 +861,7 @@ EOF
 # 2020-10-19 remove old file. remove this when all hosts updated
 rm -fv /etc/systemd/system/spamddnsfix.{timer,service}
 
-i /etc/default/spamassassin <<'EOF'
+u /etc/default/spamassassin <<'EOF'
 # defaults plus debugging flags for an issue im having
 OPTIONS="--create-prefs --max-children 5 --helper-home-dir"
 PIDFILE="/var/run/spamd.pid"
@@ -881,7 +900,7 @@ EOF
 
 m rsync -aiSAX --chown=root:root --chmod=g-s /a/bin/ds/mail-cert-cron /usr/local/bin
 
-i /etc/systemd/system/mailcert.service <<'EOF'
+u /etc/systemd/system/mailcert.service <<'EOF'
 [Unit]
 Description=Mail cert rsync
 After=multi-user.target
@@ -890,7 +909,7 @@ After=multi-user.target
 Type=oneshot
 ExecStart=/usr/local/bin/sysd-mail-once mailcert /usr/local/bin/mail-cert-cron
 EOF
-i /etc/systemd/system/mailcert.timer <<'EOF'
+u /etc/systemd/system/mailcert.timer <<'EOF'
 [Unit]
 Description=Run mail-cert once a day
 
@@ -918,8 +937,8 @@ fi
 # and see someone is banned.
 
 sed 's/^ *before *= *iptables-common.conf/before = iptables-common-exim.conf/' \
-    /etc/fail2ban/action.d/iptables-multiport.conf| i /etc/fail2ban/action.d/iptables-exim.conf
-i /etc/fail2ban/action.d/iptables-common-exim.conf <<'EOF'
+    /etc/fail2ban/action.d/iptables-multiport.conf| u /etc/fail2ban/action.d/iptables-exim.conf
+u /etc/fail2ban/action.d/iptables-common-exim.conf <<'EOF'
 # iank: same as iptables-common, except iptables is iptables-exim, ip6tables is ip6tables-exim
 
 # Fail2Ban configuration file
@@ -1015,7 +1034,7 @@ blocktype = REJECT --reject-with icmp6-port-unreachable
 iptables = /usr/local/bin/ip6tables-exim <lockingopt>
 EOF
 
-i /etc/fail2ban/jail.d/exim.local <<'EOF'
+u /etc/fail2ban/jail.d/exim.local <<'EOF'
 [exim]
 enabled  = true
 port    = 25,587
@@ -1030,7 +1049,7 @@ banaction = iptables-exim
 # 10.173.8.1 = non-nn net
 ignoreip = 209.51.188.13 2001:470:142::13 209.51.188.92 2001:470:142:3::10 72.14.176.105 2600:3c00:e000:280::2 10.173.8.1
 EOF
-if $ir; then
+if $ur; then
   m systemctl restart fail2ban
 fi
 
@@ -1136,26 +1155,26 @@ rm -fv /etc/exim4/conf.d/retry/37_retry
 
 cat >/etc/exim4/conf.d/retry/17_retry <<'EOF'
 # Retry fast for my own domains
-iankelling.org * F,1d,4m;F,14d,1h
-amnimal.ninja * F,1d,4m;F,14d,1h
-expertpathologyreview.com * F,1d,4m;F,14d,1h
-je.b8.nz * F,1d,4m;F,14d,1h
-zroe.org * F,1d,4m;F,14d,1h
-eximbackup.b8.nz * F,1d,4m;F,14d,1h
+iankelling.org * F,1d,1m;F,14d,1h
+amnimal.ninja * F,1d,1m;F,14d,1h
+expertpathologyreview.com * F,1d,1m;F,14d,1h
+je.b8.nz * F,1d,1m;F,14d,1h
+zroe.org * F,1d,1m;F,14d,1h
+eximbackup.b8.nz * F,1d,1m;F,14d,1h
 
 # The spec says the target domain will be used for temporary host errors,
 # but i've found that isn't correct, the hostname is required
 # at least sometimes.
-nn.b8.nz * F,1d,4m;F,14d,1h
-defaultnn.b8.nz * F,1d,4m;F,14d,1h
-mx.iankelling.org * F,1d,4m;F,14d,1h
-bk.b8.nz * F,1d,4m;F,14d,1h
-eggs.gnu.org * F,1d,4m;F,14d,1h
-fencepost.gnu.org * F,1d,4m;F,14d,1h
+nn.b8.nz * F,1d,1m;F,14d,1h
+defaultnn.b8.nz * F,1d,1m;F,14d,1h
+mx.iankelling.org * F,1d,1m;F,14d,1h
+bk.b8.nz * F,1d,1m;F,14d,1h
+eggs.gnu.org * F,1d,1m;F,14d,1h
+fencepost.gnu.org * F,1d,1m;F,14d,1h
 
 # afaik our retry doesnt need this, but just using everything
-mx.amnimal.ninja * F,1d,4m;F,14d,1h
-mx.expertpathologyreview.com * F,1d,4m;F,14d,1h
+mx.amnimal.ninja * F,1d,1m;F,14d,1h
+mx.expertpathologyreview.com * F,1d,1m;F,14d,1h
 
 
 mail.fsf.org * F,1d,15m;F,14d,1h
@@ -1177,27 +1196,16 @@ cd /etc/exim4
   for f in *-private.pem; do
     echo ${f%-private.pem}
   done
-} | i /etc/exim4/conf.d/my-dkim-domains
-
-if grep -Fq REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS \
-        /etc/exim4/conf.d/transport/10_exim4-config_transport-macros; then
-  cat >/etc/exim4/conf.d/transport/11_iank <<'EOF'
-# This unsets the default macro defined in on t11 in
-# /etc/exim4/conf.d/transport/10_exim4-config_transport-macros
-# It seems like a very odd choice that this has become
-# the default in t11. Normal smarthost clients use username/password
-# auth. Oh well.
-REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS ==
-EOF
-else
-  rm -f /etc/exim4/conf.d/transport/11_iank
-fi
+} | u /etc/exim4/conf.d/my-dkim-domains
+
+rm -f /etc/exim4/conf.d/transport/11_iank
 
 cat >/etc/exim4/conf.d/main/000_local <<'EOF'
 MAIN_TLS_ENABLE = true
 
 # require tls connections for all smarthosts
-REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = *
+REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = ! nn.b8.nz
+REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS = nn.b8.nz
 
 # debian exim config added this in 2016 or so?
 # it's part of the smtp spec, to limit lines to 998 chars
@@ -1209,8 +1217,8 @@ REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = *
 # other says gmail does not reject. figure out and open a new bug.
 IGNORE_SMTP_LINE_LENGTH_LIMIT = true
 
-# more verbose logs
-MAIN_LOG_SELECTOR = +all
+# more verbose logs. used to use +all, but made it less for more efficiency.
+MAIN_LOG_SELECTOR = -skip_delivery -tls_cipher -tls_certificate_verified +all_parents +address_rewrite +arguments +deliver_time +pid +queue_time +queue_time_overall +received_recipients +received_sender +return_path_on_delivery +sender_on_delivery +smtp_confirmation +subject
 
 # Based on spec, seems like a good idea to be nice.
 smtp_return_error_details = true
@@ -1269,7 +1277,7 @@ delay_warning_condition = ${if or {\
 
 # enable 587 in addition to the default 25, so that
 # i can send mail where port 25 is firewalled by isp
-daemon_smtp_ports = 25 : 587
+daemon_smtp_ports = 25 : 587 : 10025
 # default of 25, can get stuck when catching up on mail
 smtp_accept_max = 400
 smtp_accept_reserve = 100
@@ -1300,7 +1308,7 @@ fi
 
 rm -fv /etc/exim4/rcpt_local_acl # old path
 
-i /etc/exim4/conf.d/local_deny_exceptions_acl <<'EOF'
+u /etc/exim4/conf.d/local_deny_exceptions_acl <<'EOF'
 # This acl already exists in rcpt, this just makes it more widespread.
 # See the comment there for its rationale. The reason it needs to be
 # more widespread is that I've turned on sender verification, but cron
@@ -1317,7 +1325,7 @@ EOF
 
 rm -fv /etc/exim4/data_local_acl # old path
 
-i /etc/exim4/conf.d/data_local_acl <<'EOF'
+u /etc/exim4/conf.d/data_local_acl <<'EOF'
 # Except for the "condition =", this was
 # a comment in the check_data acl. The comment about this not
 # being suitable has been changed in newer exim versions. The only thing
@@ -1329,7 +1337,7 @@ i /etc/exim4/conf.d/data_local_acl <<'EOF'
 # those docs are rather old and I see a 110k spam message
 # pretty quickly looking through my spam folder.
 
-warn
+#warn
   !hosts = +iank_trusted
   remove_header = X-Spam_score: X-Spam_score_int : X-Spam_bar : X-Spam_report
 
@@ -1355,14 +1363,16 @@ EOF
 
 
 # old file
-rm -fv /etc/exim4/conf.d/router/8{8,9}0_backup_copy /etc/exim4/conf.d/router/865_backup_redir
+rm -fv /etc/exim4/conf.d/router/8{8,9}0_backup_copy \
+   /etc/exim4/conf.d/router/865_backup_redir \
+   /etc/exim4/conf.d/router/870_backup_local
 
 # It is important for this to exist everywhere except in MAIL_HOST
 # non-nn config. Previously, just had it in the nn-config on MAIL_HOST,
 # but that is a problem if we change mail host and still have something
 # in the queue which was destined for this router, but hosts were
 # unreachable, the routers will be reevaluated on the next retry.
-i /etc/exim4/conf.d/router/170_backup_copy <<EOF
+u /etc/exim4/conf.d/router/170_backup_copy <<EOF
 ### router/900_exim4-config_local_user
 #################################
 
@@ -1385,7 +1395,7 @@ EOF
 # TODO: copy the defaults into their own file, and setup a cronjob so
 # that if file.dpkg-dist shows up, and it is different, we get an alert.
 
-i /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost <<'EOF'
+u /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost <<'EOF'
 ### transport/30_exim4-config_remote_smtp_smarthost
 #################################
 
@@ -1442,7 +1452,7 @@ tls_privatekey = REMOTE_SMTP_SMARTHOST_PRIVATEKEY
 .endif
 EOF
 
-i /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp <<'EOF'
+u /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp <<'EOF'
 ### transport/30_exim4-config_remote_smtp
 #################################
 # This transport is used for delivering messages over SMTP connections.
@@ -1508,7 +1518,7 @@ tls_privatekey = REMOTE_SMTP_PRIVATEKEY
 
 EOF
 
-i /etc/exim4/conf.d/transport/30_backup_remote <<'EOF'
+u /etc/exim4/conf.d/transport/30_backup_remote <<'EOF'
 backup_remote:
   driver = smtp
   multi_domain
@@ -1551,7 +1561,7 @@ tls_privatekey = REMOTE_SMTP_SMARTHOST_PRIVATEKEY
 .endif
 EOF
 
-i /etc/exim4/conf.d/router/900_exim4-config_local_user <<'EOF'
+u /etc/exim4/conf.d/router/900_exim4-config_local_user <<'EOF'
 ### router/900_exim4-config_local_user
 #################################
 
@@ -1572,7 +1582,7 @@ local_user:
   local_part_suffix = +*
   local_part_suffix_optional
 EOF
-i /etc/exim4/conf.d/transport/30_exim4-config_dovecot_lmtp <<'EOF'
+u /etc/exim4/conf.d/transport/30_exim4-config_dovecot_lmtp <<'EOF'
 dovecot_lmtp:
   driver = lmtp
   socket = /var/run/dovecot/lmtp
@@ -1581,7 +1591,7 @@ dovecot_lmtp:
   envelope_to_add
 EOF
 
-i /etc/exim4/conf.d/transport/30_remote_smtp_vpn <<'EOF'
+u /etc/exim4/conf.d/transport/30_remote_smtp_vpn <<'EOF'
 # same as debians 30_exim4-config_remote_smtp, but
 # with interface added at the end.
 
@@ -1637,7 +1647,7 @@ tls_privatekey = REMOTE_SMTP_PRIVATEKEY
   interface = <; 10.8.0.4 ; 2600:3c00:e002:3800::4
 EOF
 
-i /etc/exim4/conf.d/transport/30_smarthost_dkim <<'EOF'
+u /etc/exim4/conf.d/transport/30_smarthost_dkim <<'EOF'
 # ian: this is remote_smtp_smarthost plus the dkim parts from remote_smtp
 
 smarthost_dkim:
@@ -1708,7 +1718,6 @@ EOF
 cat >/etc/exim4/update-exim4.conf.conf  <<'EOF'
 # default stuff, i havent checked if its needed
 dc_minimaldns='false'
-dc_relay_nets=''
 CFILEMODE='644'
 dc_use_split_config='true'
 dc_mailname_in_oh='true'
@@ -1740,8 +1749,9 @@ if mailhost; then
   # # setup chgrp www-data in ./conflink
 
   pi-nostart radicale
+  m usermod -a -G radicale iank
 
-  i /etc/systemd/system/radicale.service.d/override.conf <<EOF
+  u /etc/systemd/system/radicale.service.d/override.conf <<EOF
 [Unit]
 
 After=network.target network-online.target mailnn.service $vpnser
@@ -1873,7 +1883,7 @@ case $HOSTNAME in
     done
 
     # https://wiki.dovecot.org/SSL/DovecotConfiguration
-    i /etc/dovecot/dhparam <<'EOF'
+    u /etc/dovecot/dhparam <<'EOF'
 -----BEGIN DH PARAMETERS-----
 MIIBCAKCAQEAoleil6SBxGqQKk7j0y2vV3Oklv6XupZKn7PkPv485QuFeFagifeS
 A+Jz6Wquqk5zhGyCu63Hp4wzGs4TyQqoLjkaWL6Ra/Bw3g3ofPEzMGEsV1Qdqde4
@@ -2060,7 +2070,7 @@ namespace inbox {
 auth_mechanisms = plain login
 EOF
 
-    i /etc/dovecot/sieve-spam.sieve <<'EOF'
+    u /etc/dovecot/sieve-spam.sieve <<'EOF'
 require ["regex", "fileinto", "imap4flags"];
 
 if allof (header :regex "X-Spam-Status" "^Yes") {
@@ -2069,7 +2079,7 @@ if allof (header :regex "X-Spam-Status" "^Yes") {
 }
 EOF
 
-    i /etc/dovecot/local.conf.ext <<'EOF'
+    u /etc/dovecot/local.conf.ext <<'EOF'
 passdb {
   driver = sql
   args = /etc/dovecot/dovecot-sql.conf.ext
@@ -2081,7 +2091,7 @@ userdb {
 
 EOF
 
-    i /etc/dovecot/dovecot-sql.conf.ext <<'EOF'
+    u /etc/dovecot/dovecot-sql.conf.ext <<'EOF'
 # from mailinabox
 driver = sqlite
 # for je and bk, populated the testignore users for the relevant domains
@@ -2136,7 +2146,7 @@ if [[ $HOSTNAME == bk ]]; then
     dir=/var/www/autoconfig.$domain/html/mail
     m mkdir -p $dir
     # taken from mailinabox
-    i $dir/config-v1.1.xml <<EOF
+    u $dir/config-v1.1.xml <<EOF
 <?xml version="1.0" encoding="UTF-8"?>
 <clientConfig version="1.1">
     <emailProvider id="$domain">
@@ -2250,7 +2260,7 @@ if [[ $HOSTNAME == bk ]]; then
     mkdir -p $myncdir
 
     # copied from debians cronjob
-    i /etc/cron.d/$rcbase <<EOF
+    u /etc/cron.d/$rcbase <<EOF
 #  Roundcube database cleaning: finally removes all records that are
 #  marked as deleted.
 0   5  *   *   *   www-data $rcdir/bin/cleandb.sh >/dev/null
@@ -2310,7 +2320,7 @@ EOF
     rctmpdir=/var/tmp/$rcbase
     rcdb=/m/rc/$rcbase.sqlite
     # config from mailinabox
-    i $rcdir/config/config.inc.php <<EOF
+    u $rcdir/config/config.inc.php <<EOF
 <?php
 \$config = array();
 # debian creates this for us
@@ -2405,7 +2415,7 @@ EOF
 
     # About categories, see https://www.davx5.com/tested-with/nextcloud
     # https://github.com/blind-coder/rcmcarddav/blob/master/doc/GROUPS.md
-    i $rcdir/plugins/carddav/config.inc.php <<EOF;
+    u $rcdir/plugins/carddav/config.inc.php <<EOF;
 <?php
 \$prefs['_GLOBAL']['hide_preferences'] = false;
 \$prefs['davserver'] = array(
@@ -2475,11 +2485,11 @@ EOF
   # $rclogdir/errors.log
   # todo: consider other settings in
   # /a/opt/mailinabox/setup/nextcloud.sh
-  i /etc/php/$phpver/cli/conf.d/30-local.ini <<'EOF'
+  u /etc/php/$phpver/cli/conf.d/30-local.ini <<'EOF'
 apc.enable_cli = 1
 EOF
 
-  i /etc/php/$phpver/fpm/conf.d/30-local.ini <<'EOF'
+  u /etc/php/$phpver/fpm/conf.d/30-local.ini <<'EOF'
 date.timezone = "America/New_York"
 # for nextcloud
 upload_max_filesize = 2000M
@@ -2585,7 +2595,7 @@ EOF
         m sudo -u www-data php occ app:install $app
       fi
     done
-    i /etc/systemd/system/$ncbase.service <<EOF
+    u /etc/systemd/system/$ncbase.service <<EOF
 [Unit]
 Description=ncup $ncbase
 After=multi-user.target
@@ -2597,7 +2607,7 @@ User=www-data
 IOSchedulingClass=idle
 CPUSchedulingPolicy=idle
 EOF
-    i /etc/systemd/system/$ncbase.timer <<EOF
+    u /etc/systemd/system/$ncbase.timer <<EOF
 [Unit]
 Description=ncup $ncbase timer
 
@@ -2608,7 +2618,7 @@ OnCalendar=Daily
 WantedBy=timers.target
 EOF
     systemctl enable --now $ncbase.timer
-    i /usr/local/bin/ncup <<'EOFOUTER'
+    u /usr/local/bin/ncup <<'EOFOUTER'
 #!/bin/bash
 
 source /usr/local/lib/err
@@ -2646,7 +2656,7 @@ EOFOUTER
 
     mkdir -p /var/www/cron-errors
     chown www-data.www-data /var/www/cron-errors
-    i /etc/cron.d/$ncbase <<EOF
+    u /etc/cron.d/$ncbase <<EOF
 PATH=/usr/sbin:/sbin:/usr/bin:/bin:/usr/local/bin
 SHELL=/bin/bash
 # https://docs.nextcloud.com/server/20/admin_manual/configuration_server/background_jobs_configuration.html
@@ -2694,7 +2704,7 @@ deny
   domains = +local_domains
   !verify = recipient/callout=no_cache
 EOF
-    i /etc/exim4/conf.d/auth/29_exim4-config_auth <<'EOF'
+    u /etc/exim4/conf.d/auth/29_exim4-config_auth <<'EOF'
 dovecot_plain:
   driver = dovecot
   public_name = PLAIN
@@ -2704,7 +2714,7 @@ EOF
     ;;
 esac
 if $bhost_t; then
-  i /etc/exim4/conf.d/auth/29_exim4-config_auth <<'EOF'
+  u /etc/exim4/conf.d/auth/29_exim4-config_auth <<'EOF'
 # from 30_exim4-config_examples
 plain_server:
 driver = plaintext
@@ -2724,7 +2734,7 @@ case $HOSTNAME in
     # to see the default comments in /etc/default/exim4:
     # s update-exim4defaults --force --init
     # which will overwrite any existing file
-    i /etc/default/exim4 <<'EOF'
+    u /etc/default/exim4 <<'EOF'
 QUEUERUNNER='combined'
 QUEUEINTERVAL='30m'
 COMMONOPTIONS='-C /etc/exim4/my.conf'
@@ -2743,13 +2753,13 @@ EOF
     # note: the daemon gives up and dies after retrying those 9 times.
     # I came upon this by guessing and trial and error.
     setcap CAP_NET_BIND_SERVICE+ei /usr/sbin/exim4
-    i /etc/exim4/trusted_configs <<'EOF'
+    u /etc/exim4/trusted_configs <<'EOF'
 /etc/exim4/my.conf
 EOF
     ;;
   *)
     # default file
-    i /etc/default/exim4 <<'EOF'
+    u /etc/default/exim4 <<'EOF'
 QUEUERUNNER='combined'
 QUEUEINTERVAL='30m'
 EOF
@@ -2770,7 +2780,7 @@ case $HOSTNAME in
         dirs+=($d)
       fi
     done
-    i /etc/systemd/system/exim4.service.d/nonroot.conf <<EOF
+    u /etc/systemd/system/exim4.service.d/nonroot.conf <<EOF
 [Service]
 # see 56.2 Root privilege in exim spec
 AmbientCapabilities=CAP_NET_BIND_SERVICE
@@ -2791,7 +2801,7 @@ ProtectSystem=yes
 # when we get newer systemd
 #ProtectDevices=yes
 EOF
-    i /etc/exim4/conf.d/main/000_local-noroot <<'EOF'
+    u /etc/exim4/conf.d/main/000_local-noroot <<'EOF'
 # see 56.2 Root privilege in exim spec
 deliver_drop_privilege = true
 EOF
@@ -2803,7 +2813,7 @@ EOF
       mmm_mail4root
     )
     for f in ${files[@]}; do
-      echo "# iank: removed due to running nonroot"|i /etc/exim4/conf.d/router/$f
+      echo "# iank: removed due to running nonroot"|u /etc/exim4/conf.d/router/$f
     done
     ;;
 esac
@@ -2813,7 +2823,7 @@ case $HOSTNAME in
   # ** $MAIL_HOST|bk|je)
   $MAIL_HOST|bk|je)
 
-    echo|i /etc/exim4/conf.d/router/870_backup_local
+    echo|u /etc/exim4/conf.d/router/165_backup_local
 
     cat >>/etc/exim4/update-exim4.conf.conf <<EOF
 # note: some things we don't set that are here by default because they are unused.
@@ -2845,7 +2855,7 @@ EOF
 
 
     # no clamav on je, it has 1.5g memory and clamav uses most of it
-    i /etc/exim4/conf.d/clamav_data_acl <<'EOF'
+    u /etc/exim4/conf.d/clamav_data_acl <<'EOF'
 warn
 !hosts = +iank_trusted
 !authenticated = plain_server:login_server
@@ -2889,7 +2899,7 @@ MAIN_TLS_CERTIFICATE = /etc/exim4/fullchain.pem
 MAIN_TLS_PRIVATEKEY = /etc/exim4/privkey.pem
 EOF
 
-    i /etc/exim4/conf.d/router/190_exim4-config_fsfsmarthost <<'EOF'
+    u /etc/exim4/conf.d/router/190_exim4-config_fsfsmarthost <<'EOF'
 gnusmarthost:
   debug_print = "R: smarthost for $local_part@$domain"
   driver = manualroute
@@ -2911,7 +2921,7 @@ EOF
   # ** $MAIL_HOST)
   $MAIL_HOST)
 
-    i /etc/exim4/conf.d/router/195_dnslookup_vpn <<'EOF'
+    u /etc/exim4/conf.d/router/195_dnslookup_vpn <<'EOF'
 # copied from /etc/exim4/conf.d/router/200_exim4-config_primary, but
 # use vpn transport. lower priority so it overrides the default route.
 # Use this in case our vpn fails, we dont send anything without it.
@@ -2933,7 +2943,7 @@ EOF
     # which required using a dedicated user, but realized smtp will be
     # more reliable and less fuss. If I ever need that again, see the
     # history of this file, and bum in brc2.
-    i /etc/exim4/conf.d/router/161_backup_redir_nn <<'EOF'
+    u /etc/exim4/conf.d/router/161_backup_redir_nn <<'EOF'
 backup_redir_nn:
 driver = redirect
 # b is just an arbirary short string
@@ -2951,7 +2961,7 @@ EOF
 
     # This allows for forwarded mail to not get most rcpt checks, especially SPF,
     # which would incorrectly get denied.
-    i /etc/exim4/host_local_deny_exceptions <<'EOF'
+    u /etc/exim4/host_local_deny_exceptions <<'EOF'
 mail.fsf.org
 *.posteo.de
 EOF
@@ -2961,13 +2971,18 @@ EOF
     # case that doesn't work, we still want to accept that mail, but not
     # from any host except the smarthosts. local_hostnames and this rule
     # is for that purpose.
-    i /etc/exim4/conf.d/rcpt_local_acl <<'EOF'
+    u /etc/exim4/conf.d/rcpt_local_acl <<'EOF'
 deny
   !authenticated = *
   domains = +local_hostnames
   message = no relay
+
+# for testing bounce behavior
+#deny
+#  senders = testlist-bounces+test=zroe.org@fsf.org
+#  message = iank-bounce
 EOF
-    echo|i /etc/exim4/conf.d/router/880_universal_forward
+    echo|u /etc/exim4/conf.d/router/880_universal_forward
 
 
     cat >>/etc/exim4/conf.d/main/000_local <<EOF
@@ -2975,7 +2990,7 @@ MAILDIR_HOME_MAILDIR_LOCATION = /m/md/Sent
 EOF
 
 
-    i /etc/exim4/conf.d/router/186_sentarchive_nn <<'EOF'
+    u /etc/exim4/conf.d/router/186_sentarchive_nn <<'EOF'
 # ian: save a copy of sent mail. i thought of other ways to
 # do this, for example, to only save sent mail that is not sent
 # from my mail client which saves a copy by default, but in the
@@ -2994,7 +3009,7 @@ EOF
     # and also have mail.iankelling.org whitelisted as a relay domain.
     # I could avoid that if I changed this to submit to 587 with a
     # password like a standard mua.
-    i /etc/exim4/conf.d/router/188_exim4-config_smarthost <<'EOF'
+    u /etc/exim4/conf.d/router/188_exim4-config_smarthost <<'EOF'
 # ian: copied from /etc/exim4/conf.d/router/200_exim4-config_primary, and added senders = and
 # replaced DCsmarthost with hostname
 fsfsmarthost:
@@ -3063,6 +3078,7 @@ EOF
 # man page: is used to build the local_domains list, together with "localhost"
 # this is duplicated in a later router.
 dc_other_hostnames='iankelling.org;zroe.org;r2e.iankelling.org;mx.iankelling.org;!je.b8.nz;!bk.b8.nz;*.b8.nz;b8.nz'
+dc_relay_nets='defaultnn.b8.nz'
 EOF
 
 
@@ -3085,14 +3101,14 @@ EOF
 10.173.8.2 nn.b8.nz
 EOF
 
-    sed -r -f - /etc/init.d/exim4  <<'EOF' | i /etc/init.d/exim4in
+    sed -r -f - /etc/init.d/exim4  <<'EOF' |u /etc/init.d/exim4in
 s,/etc/default/exim4,/etc/default/exim4in,g
 s,/run/exim4/exim.pid,/run/exim4/eximin.pid,g
 s,(^[ #]*Provides:).*,\1 exim4in,
 s,(^[ #]*NAME=).*,\1"exim4in",
 EOF
     chmod +x /etc/init.d/exim4in
-    i /etc/systemd/system/exim4in.service.d/alwaysrestart.conf <<'EOF'
+    u /etc/systemd/system/exim4in.service.d/alwaysrestart.conf <<'EOF'
 [Unit]
 # needed to continually restart
 StartLimitIntervalSec=0
@@ -3103,7 +3119,7 @@ Restart=always
 RestartSec=20
 EOF
 
-    i /etc/default/exim4in <<'EOF'
+    u /etc/default/exim4in <<'EOF'
 # defaults but no queue runner and alternate config dir
 QUEUERUNNER='no'
 COMMONOPTIONS='-oP /run/exim4/eximin.pid'
@@ -3128,16 +3144,16 @@ EOF
   *)
     # this one should be removed for all non mail hosts, but
     # bk and je never become mail_host
-    echo|i /etc/exim4/conf.d/router/195_dnslookup_vpn
-    echo|i /etc/exim4/conf.d/router/160_backup_redir
-    echo|i /etc/exim4/conf.d/router/161_backup_redir_nn
-    echo|i /etc/exim4/conf.d/router/185_sentarchive
-    echo|i /etc/exim4/conf.d/router/186_sentarchive_nn
-    echo|i /etc/exim4/conf.d/router/188_exim4-config_smarthost
-    echo|i /etc/exim4/conf.d/router/190_exim4-config_fsfsmarthost
-    echo|i /etc/exim4/conf.d/rcpt_local_acl
-    echo|i /etc/exim4/conf.d/main/000_local-nn
-    echo|i /etc/exim4/conf.d/clamav_data_acl
+    echo|u /etc/exim4/conf.d/router/195_dnslookup_vpn
+    echo|u /etc/exim4/conf.d/router/160_backup_redir
+    echo|u /etc/exim4/conf.d/router/161_backup_redir_nn
+    echo|u /etc/exim4/conf.d/router/185_sentarchive
+    echo|u /etc/exim4/conf.d/router/186_sentarchive_nn
+    echo|u /etc/exim4/conf.d/router/188_exim4-config_smarthost
+    echo|u /etc/exim4/conf.d/router/190_exim4-config_fsfsmarthost
+    echo|u /etc/exim4/conf.d/rcpt_local_acl
+    echo|u /etc/exim4/conf.d/main/000_local-nn
+    echo|u /etc/exim4/conf.d/clamav_data_acl
 
 
     if $bhost_t; then
@@ -3154,7 +3170,7 @@ EOF
     fi
 
     # catches things like cronjob email
-    i /etc/exim4/conf.d/router/880_universal_forward <<'EOF'
+    u /etc/exim4/conf.d/router/880_universal_forward <<'EOF'
 universal_forward:
   driver = redirect
   domains = +local_domains
@@ -3179,7 +3195,7 @@ EOF
       if [[ -e /bu/md/cur && $(stat -c %u /bu/md/cur) == 1000 ]]; then
         chown -R Debian-exim:Debian-exim /bu/md
       fi
-      i /etc/exim4/conf.d/transport/30_backup_maildir <<EOF
+      u /etc/exim4/conf.d/transport/30_backup_maildir <<EOF
 # modified debian maildir transport
 backup_maildir:
   driver = appendfile
@@ -3192,7 +3208,7 @@ backup_maildir:
   mode_fail_narrower = false
 EOF
 
-      i /etc/exim4/conf.d/router/870_backup_local <<'EOF'
+      u /etc/exim4/conf.d/router/165_backup_local <<'EOF'
 ### router/900_exim4-config_local_user
 #################################
 
@@ -3211,7 +3227,7 @@ dc_local_interfaces='127.0.0.1;::1;$wgholeip'
 EOF
 
       # wghole & thus exim will fail to start without internet connectivity.
-      i /etc/systemd/system/exim4.service.d/backup.conf <<'EOF'
+      u /etc/systemd/system/exim4.service.d/backup.conf <<'EOF'
 [Unit]
 StartLimitIntervalSec=0
 
@@ -3234,7 +3250,7 @@ dc_eximconfig_configtype='smarthost'
 dc_smarthost='$smarthost'
 EOF
 
-    hostname -f |i /etc/mailname
+    hostname -f |u /etc/mailname
     cat >>/etc/exim4/update-exim4.conf.conf <<EOF
 # The manpage incorrectly states this will do header rewriting, but
 # that only happens if we have dc_hide_mailname is set.
@@ -3304,7 +3320,7 @@ EOF
   $MAIL_HOST)
 
 
-    i /etc/myexim4/conf.d/router/185_sentarchive <<'EOF'
+    u /etc/myexim4/conf.d/router/185_sentarchive <<'EOF'
 sentarchive:
   driver = redirect
   domains = ! +local_domains
@@ -3315,7 +3331,7 @@ sentarchive:
 EOF
 
 
-    i /etc/myexim4/conf.d/router/160_backup_redir <<'EOF'
+    u /etc/myexim4/conf.d/router/160_backup_redir <<'EOF'
 backup_redir:
 driver = redirect
 # i dont email myself from my own machine much, so lets ignore that.
@@ -3356,7 +3372,7 @@ if [[ -e /nocow ]]; then
   if ! grep -Fx "/nocow/exim4  /var/spool/exim4  none  bind  0 0" /etc/fstab; then
     echo "/nocow/exim4  /var/spool/exim4  none  bind  0 0" >>/etc/fstab
   fi
-  i /etc/systemd/system/exim4.service.d/override.conf <<'EOF'
+  u /etc/systemd/system/exim4.service.d/override.conf <<'EOF'
 [Unit]
 # without local-fs on exim, we get these kind of errors in paniclog on shutdown:
 # Failed to create spool file /var/spool/exim4//input//1jCLxz-0008V4-V9-D: Permission denied
@@ -3410,14 +3426,20 @@ if $reload; then
   m systemctl daemon-reload
 fi
 
-# checking bhost_t is redundant, but could help us catch errors.
-if $bhost_t || [[ -e /etc/wireguard/wghole.conf ]]; then
-  # todo: in mail-setup, we have a static list of backup hosts, not *y
-  m systemctl --now enable wg-quick@wghole
+# optimization, this only needs to run once.
+if [[ ! -e /sys/class/net/wghole ]]; then
+  # checking bhost_t is redundant, but could help us catch errors.
+  if $bhost_t || [[ -e /etc/wireguard/wghole.conf ]]; then
+    # todo: in mail-setup, we have a static list of backup hosts, not *y
+    m systemctl --now enable wg-quick@wghole
+  fi
 fi
 
-sysd-prom-fail-install epanicclean
-m systemctl --now enable epanicclean
+# optimization, this only needs to be run once
+if [[ ! -e /var/lib/prometheus/node-exporter/exim_paniclog.prom ]]; then
+  sysd-prom-fail-install epanicclean
+  m systemctl --now enable epanicclean
+fi
 
 case $HOSTNAME in
   je)
@@ -3428,8 +3450,11 @@ case $HOSTNAME in
     ;;
 esac
 
-m /a/bin/ds/mail-cert-cron -1
-sre mailcert.timer
+# optimization, this only needs to run once.
+if [[ ! -e /etc/exim4/fullchain.pem ]]; then
+  m /a/bin/ds/mail-cert-cron -1
+  m systemctl --now enable mailcert.timer
+fi
 
 case $HOSTNAME in
   $MAIL_HOST|bk)
@@ -3466,9 +3491,11 @@ case $HOSTNAME in
   $MAIL_HOST|bk|je)
     # start spamassassin/dovecot before exim.
     sre dovecot spamassassin
-    # need to wait a bit before restarting exim, else I
-    # get a paniclog entry like: spam acl condition: all spamd servers failed
-    sleep 3
+    # Wait a bit before restarting exim, else I get a paniclog entry
+    # like: spam acl condition: all spamd servers failed. But I'm tired
+    # of waiting. I'll deal with this some other way.
+    #
+    # sleep 3
     m systemctl --now enable mailclean.timer
     ;;&
   $MAIL_HOST)
@@ -3527,7 +3554,7 @@ case $HOSTNAME in
     # note: cronjob "ian" also does some important monitoring
     # todo: this will sometimes cause an alert because mailtest-check will run
     # before we have setup network namespace and spamassassin
-    i /etc/cron.d/mailtest <<EOF
+    u /etc/cron.d/mailtest <<EOF
 SHELL=/bin/bash
 PATH=/usr/bin:/bin:/usr/local/bin
 MAILTO=daylert@iankelling.org
@@ -3540,7 +3567,7 @@ EOF
 
     m sudo rsync -ahhi --chown=root:root --chmod=0755 \
       /b/ds/mailtest-check /b/ds/check-remote-mailqs /usr/local/bin/
-    i /etc/systemd/system/mailtest-check.service <<'EOF'
+    u /etc/systemd/system/mailtest-check.service <<'EOF'
 [Unit]
 Description=mailtest-check
 After=local-fs.target
@@ -3589,7 +3616,7 @@ EOF
     # Dont put these test messages into the sent folder or else it will
     # overwhelm it, plus i dont want to save a copy at all.
     # Plus addresses we generally want to ignore.
-    i /etc/exim4/ignore-sent <<EOF
+    u /etc/exim4/ignore-sent <<EOF
 $(printf "%s\n" ${test_tos[@]})
 vojdedIdNejyebni@b8.nz
 b@eximbackup.b8.nz