OpenSMTPD with sender dependent smart hosts


aptitude install opensmtpd


The main config resides in /etc/smtpd.conf. In this case it enables authenticated users to relay to several smart hosts depending on the sender of the email. Thus, users can send from with their non-local adresses and OpenSMTPD knows where to forward it:

# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.

# Certificates for SSL and TLS
pki domain.example certificate "/etc/letsencrypt/live/domain.example/cert.pem"
pki domain.example key "/etc/letsencrypt/live/domain.example/privkey.pem"

# Accept local mail
listen on localhost
listen on

# Accept external mail when authenticated over a secure channel, authenticated user are considered local!
listen on smtps pki domain.example auth

listen on smtps pki domain.example auth

#listen on port 465 tls pki domain.example auth

# If you edit the file, you have to run "smtpctl update table aliases"
table aliases file:/etc/aliases

# Forward mail for local accounts to their inbox
accept for local alias  deliver to mda "/usr/lib/dovecot/dovecot-lda -k"
accept from source for local alias  deliver to mda "/usr/lib/dovecot/dovecot-lda -k"

# Table for smtp-auth credentials, has to be created with "makemap /etc/smtpd_auth"
table smtp_auth_db db:/etc/smtpd_auth.db

# Accept mail from known mail accounts and forward them to their respective smarthosts using smtp-auth
accept from local sender some_user@mailprovider.example for any relay via tls+auth://some_user_mailprovider@mailprovider.example auth

accept for any relay

Authorization data is located in /etc/smtpd_auth:

some_user_mailprovider username:password

After changing it the database has to be updated via makemap /etc/smtpd_auth. Authorization databases need to be readable by the user opensmtpd and should be protected from other users:

chmod 600 /etc/smtpd.conf /etc/smtpd_auth*
chown root.root /etc/smtpd.conf /etc/smtpd_auth
chown opensmtpd.opensmtpd /etc/smtpd_auth.db

/etc/aliases had to be updated to redirect root mails to an actual user.

Dovecot & Getmail


aptitude install dovecot-imapd dovecot-sieve getmail4


Overwriting predefined values via /etc/dovecot/local.conf:

# SSL configuration
ssl = required
ssl_cert = </etc/letsencrypt/live/domain.example/cert.pem
ssl_key = </etc/letsencrypt/live/domain.example/privkey.pem

# Where to put received mail

# Enable zlib plugin globally for reading/writing
mail_plugins = $mail_plugins zlib

# Enable compression while saving
plugin {
  zlib_save_level = 9
  zlib_save = xz

# Enable sieve filtering for local delivery agent
protocol lda {
  mail_plugins = $mail_plugins sieve

# Restrict plain imap protocol
service imap-login {
  inet_listener imap {
    address = #Listen only on loopback
    #port = 0 #This disables it completely

# Fix stats-writer issue for Debian 10 (see
service stats {
  unix_listener stats-writer {
    mode = 0666

User defined filtering can be achieved via ~/.dovecot.sieve files.

Getmail configurations need the following destination section to forward mails to dovecot:

type = MDA_external
path = /usr/lib/dovecot/deliver

Collecting mails regularly can be done via cron:

@hourly getmails -q

Let’s Encrypt SSL Certificates

Installing certbot

aptitude install certbot

Running certbot

Certbot can use its own simple webserver when no webserver is installed so that certificates for mail servers etc. can be obtained:

certbot certonly --rsa-key-size 4096 --standalone \
  --pre-hook  "systemctl stop lighttpd opensmtpd dovecot" \
  --post-hook "cat /etc/letsencrypt/live/domain1.example/cert.pem /etc/letsencrypt/live/domain1.example/privkey.pem > /etc/letsencrypt/live/domain1.example/cert+privkey.pem && chmod 600 /etc/letsencrypt/archive/*/*.pem && systemctl start dovecot opensmtpd lighttpd" \
  -d domain1.example -d domain2...


The certbot packages provides its own entries for cron and systemd thus no own mechanism is needed. Hook mechanism can be later edited also in /etc/letsencrypt/renewal/domain1.example.conf

OpenSSH Daemon

Copy the current active ssh-agent key to the new host before disabling password authentication: ssh-copy-id user@hostname

The following values are changed from their default values in /etc/ssh/sshd_config:

  • Disable root login under any circumstances: PermitRootLogin no
  • Disable password authentification: PasswordAuthentication no
  • Check for inactive connections after 5 minutes: ClientAliveInterval 300
  • Drop inactive connections after 3 tries without response:ClientAliveCountMax 3
  • Allow only known users: AllowUsers user_a user_b user_c@host_x
  • Disable X11-Forwarding (why would you do that on a server?): X11Forwarding no

Install fail2ban to blacklist malicious accesses:

aptitude install fail2ban

Check in /etc/fail2ban/jail.d/defaults-debian.conf that SSH checking is enabled:

enabled = true

Remotely unlocking LUKS encrypted headless system

Define a fixed IP address for initramfs in /etc/initramfs-tools/initramfs.conf otherwise the kernel will try to get an address via DHCP (eth0 has to be adapted to the actual network card for Debian Stretch, such as enp3s0):


Install dropbear which automatically gets installed into the initramfs and implicitly updates the initramfs image:

apt-get install dropbear
  • For Debian Stretch/Buster this ends with the following warning: dropbear: WARNING: Invalid authorized_keys file, remote unlocking of cryptroot via SSH won't work! The reason is that dropbear no longer generates a default key anymore. Thus, copy your own public key into /etc/dropbear-initramfs/authorized_keys and run update-initramfs -u which should not show the warning above again. Afterwards copy your private key to a client machine. To finally¬† resolve the key-mismatch warnings, let dropbear listen on a different port by changing DROPBEAR_OPTIONS to "-p 2222 -s -j -k -I 30" in /etc/dropbear-initramfs/config. This prevents port forwarding, password logins, and sets an inactivity timeout. Additionally, set IFDOWN=none to keep any network settings. This later lets opensmtpd start cleanly on boot (otherwise it complains not finding its network device to listen on). Run update-initramfs -u to activate these settings for the next reboot.
  • For Debian Jessie copy the newly generated /etc/initramfs-tools/root/.ssh/id_rsa to a client machine.

Add the following on a clients .ssh/config file to avoid key-mismatch errors stemming from entries in known_hosts:

Host debian_unlock
  User root
  Port 22 # or whatever is used for dropbear
  IdentityFile path/to/previously/copied/private_key

To unlock the drives on boot-up ssh debian8_unlock into the system. ps will print the needed cryptsetup command:

# ps
124 root /sbin/dropbear
133 root {cryptroot} /bin/sh /scripts/local-top/cryptroot
138 root /lib/cryptsetup/askpass Please unlock disk sda5_crypt:
139 root /sbin/cryptsetup -T 1 open --type luks /dev/disk/by-uuid/715ac060-2efc-491a-9c96-6898e18c01bd sda5_crypt --key-file=-

Copy the cryptsetup command which will ask for your passphrase and unlocks your drive.

Debian Jessie: The askpass process still prevents booting up (as it is asking on the boot console which nobody sees) so kill -9 that one to continue the boot process.

Debian Buster: Run cryptroot-unlock only, this will ask for the password and continues booting afterwards.