Add systemd units (examples)
authorHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Sat, 22 Oct 2022 21:15:44 +0000 (23:15 +0200)
committerHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Thu, 19 Oct 2023 07:56:29 +0000 (09:56 +0200)
- daemon
- socket activation
- socket activation (inetd mode)
- queuerunner
- maintainance

15 files changed:
.gitignore
configs/ABOUT
configs/system-integration/README.md [new file with mode: 0644]
configs/system-integration/systemd/.gitignore [new file with mode: 0644]
configs/system-integration/systemd/README.md [new file with mode: 0644]
configs/system-integration/systemd/daemon/exim.service [new file with mode: 0644]
configs/system-integration/systemd/inetd/exim.socket [new file with mode: 0644]
configs/system-integration/systemd/inetd/exim@.service [new file with mode: 0644]
configs/system-integration/systemd/install [new file with mode: 0755]
configs/system-integration/systemd/maintenance/exim-maintenance.service [new file with mode: 0644]
configs/system-integration/systemd/maintenance/exim-maintenance.timer [new file with mode: 0644]
configs/system-integration/systemd/queuerunner/exim-queuerunner.service [new file with mode: 0644]
configs/system-integration/systemd/queuerunner/exim-queuerunner.timer [new file with mode: 0644]
configs/system-integration/systemd/socket/exim.service [new file with mode: 0644]
configs/system-integration/systemd/socket/exim.socket [new file with mode: 0644]

index 8c2660a9fca0d0e641343dc9cb10d63744cc735d..c55dcdcdd644fd96aebd2ecfe364b52d88c336b3 100644 (file)
@@ -1,4 +1,4 @@
-exim-*
+!/system-integration/
 !/test/aux-fixed/exim-ca
 *~
 *.bak
index 13d9230b6d24c848c1613ae9888bced3d0799e94..f47f96aa81b7886e580a3a84180a13fc9d06c41f 100644 (file)
@@ -1,7 +1,8 @@
-Exim repository: configs
-------------------------
+Exim repository: configs/
+-------------------------
 
-This directory contains sample configurations and similar files that have been
-submitted by Exim users. The files are not locally modified.
+This directory contains sample configurations and and files for
+integrating Exim with the system. These have been submitted by Exim
+users and may or may not fit your your environment.
 
-End
+But we're interested in feedback and improvements.
diff --git a/configs/system-integration/README.md b/configs/system-integration/README.md
new file mode 100644 (file)
index 0000000..d06afc5
--- /dev/null
@@ -0,0 +1,8 @@
+# System Integration
+
+Various systems use various ways to integrate Exim with the system.
+Mainly these tasks have to be accomplished:
+
+- startup procedure (running as a service or on demand)
+- queue runs
+- regular maintenance tasks (log rotation, database cleanup)
diff --git a/configs/system-integration/systemd/.gitignore b/configs/system-integration/systemd/.gitignore
new file mode 100644 (file)
index 0000000..15c1e5d
--- /dev/null
@@ -0,0 +1 @@
+.installed
diff --git a/configs/system-integration/systemd/README.md b/configs/system-integration/systemd/README.md
new file mode 100644 (file)
index 0000000..297edbc
--- /dev/null
@@ -0,0 +1,86 @@
+# Systemd Unit Examples for Exim
+
+This directory contains several examples for Systemd units to manage an Exim installation.
+There is room for improvement, so please share your ideas or setups that are proven to work
+in your environment.
+
+All the service units try to protect the system from unintentional
+writes to locations outside of Exim's spool, and log directories.  You
+may need to override specific settings, we recommend using Systemd's
+override mechanism (`systemd edit …`).
+
+The .service units use `ProtectSystem=strict`, which implies a read-only
+file system structure. Exim needs write access to the spool directory
+(main config option: `spool_directory`), and the log directory (main
+config option: `log_file_path`). For improved security you can even set
+`NoNewPrivileges`, if you don't do local deliveries.
+
+The provides Systemd units are examples, containing placeholders
+`{{…}}`. The [install script](./install) helps substituting them.\1av
+The following placeholders are used currently:
+- `exim`:
+- `spooldir:`
+- `logdir`:
+
+
+## Daemon
+
+This is best suited for *average to high traffic systems*, it engages
+all built-in Exim facilities, as queue runner management and system load
+depending message processing.
+
+The [systemd service unit](./daemon/exim.service) starts the Exim main
+process. This process listens on the ports configured in the _runtime
+configuration_ (typically `exim.conf`), and supervises all other
+activities, including management of queue runner startups. Basically it
+calls `exim -odf -q...`.
+
+For regular maintenance tasks (database cleanup) additional units are
+[required](./maintenance).
+
+## Socket
+
+This is best suited for *low traffic* systems, which experience a
+message *burst* from time to time. Regular desktop, and edge systems fit this
+pattern.
+
+Exim's start is delayed until the first connection. Once a connection is
+initiated, Exim starts a listener on the port configured in the [systemd
+socket unit](./socket/exim.socket) and waits for more connections. It
+exits after being idle for a while. Basically it calls `exim -bw ...`.
+
+Additional [_queue runner_ timer and service units](#queue-runner) are required.
+
+For regular maintenance tasks (database cleanup)
+additional units are [required](./maintenance).
+
+## Inetd
+
+This is best suited for systems with *low traffic*, if the
+[socket](#socket) approach doesn't work.
+
+For each incoming connection a new Exim instance starts, handling
+exactly this connection and then exits. The listener port is configured
+in the [systemd socket unit](./inetd/exim.socket).
+
+Additional [_queue runner_ timer and service units](#queue-runner) are required.
+
+For regular maintenance tasks (database cleanup)
+additional units are [required](./maintenance).
+
+## Queue Runner
+
+This is a *timer*, and a *service* unit which starts Exim queue runner
+processes. This is necessary, as the socket activated Exim instances
+(from [socket](#socket) and [inetd](#inetd) do not care, once the first
+delivery attempt is done.
+
+## Maintenance
+
+This is a *timer* unit, and a *service* unit for regular maintenance
+tasks.  For security it is recommended to use the `User=` Systemd
+directive in a local override file.
+
+The service unit cares about tidying Exim's hint databases. It *does
+not* rotate the log files, as most systems have their own mechanism for
+doing this job (e.g. Logrotate).
diff --git a/configs/system-integration/systemd/daemon/exim.service b/configs/system-integration/systemd/daemon/exim.service
new file mode 100644 (file)
index 0000000..5d49ab3
--- /dev/null
@@ -0,0 +1,29 @@
+[Unit]
+Description=Exim MTA (as daemon)
+Documentation=man:exim
+Documentation=https://exim.org/docs.html
+
+Requires=network.target
+After=networking.target
+
+[Service]
+Environment=DAEMON_OPTS=
+Environment=QUEUE_OPTS=-q15m
+EnvironmentFile=-/etc/default/{{exim}}
+
+Type=exec
+ExecStart={{exim}} -bdf $DAEMON_OPTS $QUEUE_OPTS
+ExecReload=kill -HUP ${MAINPID}
+
+# If you do not need local deliveries, enabling the
+# next option can improve security
+#NoNewPrivileges=yes
+
+ProtectSystem=strict
+ReadWriteDirectories={{spooldir}}
+ReadWriteDirectories={{logdir}}
+
+Slice=exim.slice
+
+[Install]
+WantedBy=multi-user.target
diff --git a/configs/system-integration/systemd/inetd/exim.socket b/configs/system-integration/systemd/inetd/exim.socket
new file mode 100644 (file)
index 0000000..a802e8e
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=Exim MTA (inetd)
+Documentation=man:exim
+Documentation=https://exim.org/docs.html
+
+[Socket]
+ListenStream=25
+Accept=yes
+
+[Install]
+WantedBy=sockets.target
diff --git a/configs/system-integration/systemd/inetd/exim@.service b/configs/system-integration/systemd/inetd/exim@.service
new file mode 100644 (file)
index 0000000..7771fde
--- /dev/null
@@ -0,0 +1,27 @@
+[Unit]
+Description=Exim MTA (socket activated - inetd mode)
+Documentation=man:exim
+Documentation=https://exim.org/docs.html
+
+[Service]
+Type=exec
+
+# We can't use -odf, as this would ask exim to keep the connection
+# from the client open until the delivery is done
+ExecStart={{exim}} -bs
+
+StandardInput=socket
+StandardError=journal
+
+# Don't kill the delivery process we spawned as a child
+KillMode=process
+
+# If you do not need local deliveries, enabling the
+# next option can improve security
+#NoNewPrivileges=yes
+
+ProtectSystem=strict
+ReadWriteDirectories={{spooldir}}
+ReadWriteDirectories={{logdir}}
+
+Slice=exim.slice
diff --git a/configs/system-integration/systemd/install b/configs/system-integration/systemd/install
new file mode 100755 (executable)
index 0000000..83a648a
--- /dev/null
@@ -0,0 +1,92 @@
+#!/bin/bash
+# simple helper, mainly for testing the provided Systemd units.
+
+set -eu
+export LC_ALL=C
+
+: ${EXIM=exim}
+: ${EXIM_LOGDIR=/var/log/exim}
+: ${EXIM_SPOOLDIR=/var/spool/exim}
+
+# Packagers should install to $(systemd-path systemd-system-unit)
+# which mostly is something like /lib/systemd/system
+dstdir=
+
+usage="$0 [OPTIONS] variant...
+  This simple script installs Systemd unit files to the desired destination, replacing
+  the {{Placeholder}}s.
+
+  VARIANT: one of daemon, inet, socket, maintainance, queuerunner
+
+  OPTIONS:
+  --help          print this help and exit cleanly
+  --uninstall|-u  uninstall the installed files
+  --dstdir|-d DIR the destination directory (mandatory, use 'DEFAULT'
+                  to use Systemd's default location (`systemd-path systemd-system-conf`)
+
+  Placeholders:
+  {{exim}} from \$EXIM ($EXIM)
+  {{logdir}} from \$EXIM_LOGDIR ($EXIM_LOGDIR)
+  {{spooldir}} from \$EXIM_SPOOLDIR ($EXIM_SPOOLDIR)
+"
+
+
+tmp=$(getopt -n $0 -o d:n --long dstdir:,help,uninstall -- "$@")
+eval set -- "$tmp"
+while true
+do
+       o=$1; shift
+       case $o in
+                -d|--dstdir) dstdir=$1; shift;;
+                --help) echo "$usage"; exit;;
+               -n|--uninstall) uninstall=1;;
+               --) break
+       esac
+done
+
+if [[ -v uninstall ]]
+then
+       if ! [[ -r .installed ]]
+       then
+               echo "$0: noting to uninstall (.installed is empty or isn't readable)" >&2
+               exit
+       fi
+
+       rm -vf $(<.installed)
+       rm -f .installed
+       exit
+fi
+
+case $dstdir in
+        DEFAULT) dstdir=$(systemd-path systemd-system-conf);;
+        "") echo "$0: --dstdir is mandatory" >&2; exit 1;;
+        *) ;;
+esac
+
+if (( $# == 0 ))
+then echo "$0: need variant" >&2; exit 1;
+fi
+
+function xform() {
+        sed -e "s|{{exim}}|${EXIM:?}|g" \
+            -e "s|{{logdir}}|${EXIM_LOGDIR:?}|g" \
+            -e "s|{{spooldir}}|${EXIM_SPOOLDIR:?}|g"
+}
+
+for dir in ${@:?need source dir(s)}
+do
+               echo "# $dir"
+               for src in "$dir"/*
+               do
+                       dst="$dstdir/${src##*/}"
+                       echo "installing $dst"
+                       xform <"$src" >"$dst"
+                       echo $dst >> .installed
+               done
+done
+
+if [[ $dstdir == $(systemd-path systemd-system-conf) ]]
+then
+        echo "# reloading systemd configuration"
+        systemctl daemon-reload
+fi
diff --git a/configs/system-integration/systemd/maintenance/exim-maintenance.service b/configs/system-integration/systemd/maintenance/exim-maintenance.service
new file mode 100644 (file)
index 0000000..42722d3
--- /dev/null
@@ -0,0 +1,24 @@
+[Unit]
+Description=Exim MTA (maintenance)
+Documentation=man:exim
+Documentation=https://exim.org/docs.html
+
+[Service]
+Type=oneshot
+ExecReload=kill -HUP ${MAINPID}
+
+# Dollars are doubled for systemd!
+WorkingDirectory={{spooldir}}
+ExecStart=sh -ec 'for db in db/* ;\
+               do \
+                       test -f "$$db" && [ "$${db##*.}" != lockfile ] || continue ;\
+                       exim_tidydb $$PWD "$${db##*/}"; \
+               done'
+
+ProtectSystem=strict
+ReadWriteDirectories={{spooldir}}/db
+
+Slice=exim.slice
+
+[Install]
+WantedBy=multi-user.target
diff --git a/configs/system-integration/systemd/maintenance/exim-maintenance.timer b/configs/system-integration/systemd/maintenance/exim-maintenance.timer
new file mode 100644 (file)
index 0000000..bd192cd
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=Exim MTA (maintenance timer)
+Documentation=man:exim
+Documentation=https://exim.org/docs.html
+
+[Timer]
+OnActiveSec=1h
+OnUnitActiveSec=1d
+
+[Install]
+WantedBy=timers.target
diff --git a/configs/system-integration/systemd/queuerunner/exim-queuerunner.service b/configs/system-integration/systemd/queuerunner/exim-queuerunner.service
new file mode 100644 (file)
index 0000000..e6e9ca7
--- /dev/null
@@ -0,0 +1,21 @@
+[Unit]
+Description=Exim MTA (queue runner service)
+Documentation=man:exim
+Documentation=https://exim.org/docs.html
+
+[Service]
+Type=oneshot
+
+ExecStart={{exim}} -q
+KillMode=process
+
+# If you do not need local deliveries, enabling the
+# next option can improve security
+#NoNewPrivileges=yes
+
+ProtectSystem=strict
+ReadWriteDirectories={{spooldir}}
+ReadWriteDirectories={{logdir}}
+ReadWriteDirectories=/var/mail /var/spool/mail
+
+Slice=exim.slice
diff --git a/configs/system-integration/systemd/queuerunner/exim-queuerunner.timer b/configs/system-integration/systemd/queuerunner/exim-queuerunner.timer
new file mode 100644 (file)
index 0000000..6988b7c
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=Exim MTA (queue runner timer)
+Documentation=man:exim
+Documentation=https://exim.org/docs.html
+
+[Timer]
+OnActiveSec=120
+OnUnitActiveSec=15m
+
+[Install]
+WantedBy=timers.target
diff --git a/configs/system-integration/systemd/socket/exim.service b/configs/system-integration/systemd/socket/exim.service
new file mode 100644 (file)
index 0000000..a4576ae
--- /dev/null
@@ -0,0 +1,26 @@
+[Unit]
+Description=Exim MTA (socket activated)
+Documentation=man:exim
+Documentation=https://exim.org/docs.html
+PartOf=exim.socket
+
+[Service]
+Type=exec
+Environment=INACTIVITY_TIMEOUT=5m
+EnvironmentFile=-/etc/default/exim
+
+ExecStart=exim -bw${INACTIVITY_TIMEOUT}
+
+StandardInput=socket
+StandardError=journal
+
+# If you do not need local deliveries, enabling the
+# next option can improve security
+#NoNewPrivileges=yes
+
+ProtectSystem=strict
+ReadWriteDirectories={{spooldir}}
+ReadWriteDirectories={{logdir}}
+ReadWriteDirectories=/var/mail /var/spool/mail
+
+Slice=exim.slice
diff --git a/configs/system-integration/systemd/socket/exim.socket b/configs/system-integration/systemd/socket/exim.socket
new file mode 100644 (file)
index 0000000..8b38766
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=Exim MTA (socket)
+Documentation=man:exim
+Documentation=https://exim.org/docs.html
+
+[Socket]
+ListenStream=25
+
+[Install]
+WantedBy=sockets.target