Nginx can be used to proxy several mail protocols. This can be useful in a variety of scenarios: load balancing, providing up-to-date TLS for servers that don’t support it, graceful server migration, or enabling user-specific storage policies.
Unfortunately, what’s not clear from the documentation is that nginx (at least at 1.18
) can’t proxy over encrypted connections - which makes this unworkable except in the case of servers on the local network.
However, you can instead put nginx in front of stunnels to enable this.
For this example we'll configure nginx to route IMAP requests for user bob
to oldmail.example.com
and requests for alice
to newmail.example.com
.
This assumes a server running Ububtu 22.04 with IPv6 enabled.
The first tricky aspect of the nginx configuration is the nginx auth server, but if you think of it as a username-based router, rather than authenticator, it makes more sense. You don't have to check passwords, you don't even have to check for a valid user.
We'll set up a simple auth server on http://[::1]:8081/auth_imap
-
Add the file
/etc/nginx/sitate-available/mailauth.conf
# /etc/nginx/sites-available/mailauth.conf map $http_auth_user $authstatus { "alice" OK; "bob" OK; default "[AUTHENTICATIONFAILED] Authentication failed."; } map $http_auth_user $authport { "bob" 8998; default 8997; } server { listen [::1]:8081; location /auth_imap { add_header Auth-Status $authstatus; add_header Auth-Server ::1; add_header Auth-Port $authport; return 204; } location / { return 404; } }
-
Enable the site and reload nginx
ln -s /etc/nginx/sites-available/mailauth.conf /etc/nginx/sites-enabled/
-
Add a configuration file
/etc/nginx/mail.conf
# /etc/nginx/mail.conf mail { server_name mail.example.com; ssl_certificate /etc/letsencrypt/live/mail.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/mail.example.com/privkey.pem; server { listen [::]:993 ssl; listen 993 ssl; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5; ssl_session_timeout 10m; protocol imap; imap_auth plain; proxy_pass_error_message on; auth_http http://[::1]:8081/auth_imap; auth_http_header User-Agent "nginx_mail_imap"; } }
-
Edit
/etc/nginx/nginx.conf
to include the following (near the bottom)include /etc/nginx/mail.conf;
-
Reload nginx
systemctl reload nginx
-
Install stunnel
apt install stunnel
-
Add the config files into
/etc/stunnel/
# /etc/stunnel/imaps-8997.conf client = yes foreground = yes connect = newmail.example.com:imaps
# /etc/stunnel/imaps-8998.conf client = yes foreground = yes connect = oldmail.example.com:imaps
-
Add systemd socket files for the ports
# /etc/systemd/system/imaps-8997.socket [Unit] Description=Stunnel socket for IMAPS proxy 8997 [Socket] ListenStream=[::1]:8997 Accept=yes NoDelay=yes [Install] WantedBy=sockets.target
# /etc/systemd/system/imaps-8998.socket [Unit] Description=Stunnel socket for IMAPS proxy 8998 [Socket] ListenStream=[::1]:8998 Accept=yes NoDelay=yes [Install] WantedBy=sockets.target
-
Add the corresponding service files
# /etc/systemd/system/[email protected] [Unit] Description=Stunnel socket for IMAPS proxy 8997 [Service] Type=simple StandardInput=socket StandardOutput=socket StandardError=journal ProtectHome=yes ProtectSystem=strict PrivateTmp=yes ExecStart=/usr/bin/stunnel4 /etc/stunnel/imaps-8997.conf [Install] WantedBy=multi-user.target
# /etc/systemd/system/[email protected] [Unit] Description=Stunnel socket for IMAPS proxy 8998 [Service] Type=simple StandardInput=socket StandardOutput=socket StandardError=journal ProtectHome=yes ProtectSystem=strict PrivateTmp=yes ExecStart=/usr/bin/stunnel4 /etc/stunnel/imaps-8998.conf [Install] WantedBy=multi-user.target
-
Enable the sockets
systemctl enable imaps-8997.socket --now systemctl enable imaps-8998.socket --now
-
Use
nc
to check the tunnels are working$ nc ::1 8997 * OK [CAPABILITY IMAP4...
-
Generate some good and bad login strings using base64
$ echo -en "\0bob\0goodpass" | openssl base64 AGJvYgBnb29kcGFzcw== $ echo -en "\0bob\0badpass" | openssl base64 AGJvYgBiYWRwYXNz
-
Use
s_client
for interactive sessions$ openssl s_client -connect mail.example.com:993 [...] * OK IMAP4 ready A AUTHENTICATE PLAIN AGJvYgBnb29kcGFzcw== A OK [CAPABILITY ...] A LOGOUT * BYE Logging out A OK LOGOUT completed closed
$ openssl s_client -connect mail.example.com:993 [...] * OK IMAP4 ready A AUTHENTICATE PLAIN AGJvYgBiYWRwYXNz A NO [AUTHENTICATIONFAILED] Authentication failed. closed