SMTP via ssh tunnel using systemd

This setup describes how to set up a ssh tunnel to a remote SMTP server on-demand using a socket-based activation of systemd. The set-up is essentially the same as described in this article but uses systemd instead of inetd.

Server setup

On the client computer, generate an ssh key pair and copy the public key to the SMTP server:

ssh-keygen -t ed25519 -f /root/.ssh/tunnel_key
ssh-copy-id -i /root/.ssh/tunnel_key user@mx.example.com

Log in to the server and edit the ~/.ssh/authorized_keys and add command 'command="nc localhost 25", no-X11-forwarding, no-agent-forwarding, no-port-forwarding' in front of the line containing the public key. The line in your ~/.ssh/authorized_keys file looks now like:

command="nc localhost 25",no-X11-forwarding,no-agent-forwarding,no-port-forwarding ssh-ed25519 AAAAC3Nz…

If everything is set up correctly (the nc command is installed and in the path, the sshd is set-up correctly…) then you should be able to connect from the client computer and see the SMTP banner:

ssh -i /root/.ssh/tunnel_key user@mx.example.com
220 mx.example.com ESMTP Postfix (Debian/GNU)
quit
221 2.0.0 Bye

Make sure to connect at least once from the local root account in order to accept the server's key, otherwise the systemd socket will time out.

Client computer setup

Set up a pair of systemd socket and service files for the automatic socket activation of the tunnel. First, create a /etc/systemd/system/smtp-submission.socket file with content:

[Unit]
Description=SSH Tunnel to mx.example.com for SMTP submissions

[Socket]
ListenStream=25
Accept=yes

[Install]
WantedBy=sockets.target

If you want to accept only connections from the local host, change the setting to something like ListenStream=[::1]:25.

Then create a /etc/systemd/system/smtp-submission@.service file with content:

[Unit]
Description=SSH Tunnel to mx.example.com for SMTP submissions

[Service]
ExecStart=-/usr/bin/ssh -q -T -i /root/.ssh/tunnel_key user@mx.example.com
StandardInput=socket

Finally enable and activate the service:

systemctl enable smtp-submission.socket
systemctl start smtp-submission.socket
systemctl status smtp-submission.socket

You should now be able to connect to the SMTP port on the client computer (localhost:25) and talk to the remote server over the ssh tunnel. Happy mailing.