Last Updated on 2018-06-08.
[:en]Because of the EU GDPR / DSGVO regulations it is recommended to run websites secured with SSL certificates, therefore using port 443 instead of 80.
But especially in small organizations the port 443 has already been used, in most cases for the various tools of MS Exchange Server.
Changing to alternative ports for certain services globally often is de facto not realizable, so one solution can be a webserver’s reverse proxy feature which I will explain here.
This tutorial is tested with and should work with Ubuntu/Apache2 as public webserver, Windows 2016 Server for Exchange Server 2016 and Outlook 2016, using SSL certificates from Let’s Encrypt.
Basically, our webserver will be our new public port 443 access point. It will handle all HTTPS web requests and will also forward data to Exchange if necessary.
So in the end, we need to have valid SSL certificates on the webserver and on the Exchange server. For Exchange, we copy the certificate from the webserver and import it (creating it “live” on Exchange is hardly possible in this case due to the webserver’s needed proxy settings).
Router / Firewall
In your router config, create a new NAT rule which allows you to quickly switch incoming port 443 forwarding from mailserver to webserver. Do not enable it at this point, we will need that later.
If you use external DNS providers with automatic HTTP(S) proxies to speed up your website like Cloudflare, you might want to disable it (at least the proxy features) for the time of the configuration process, as it can produces some unpredictable behaviour in combination with the browser cache, tests etc.
Webserver / WordPress
You might also want to temporarily disable plugins for first tests like WP Super Cache, Minify etc. to get immediate results of the changes.
First we install Let’s Encrypt’s Certbot . Make a snapshot or backup before, then run it without any parameters. It shows a user friendly wizard which assists you in converting your existing Apache Virtual Hosts to SSL enabled websites. If everything runs fine, you have your websites easily prepared for HTTPS and Apache is configured automatically.
Note for Cloudflare
If you are using web cache/proxy services, certbot/letsencrypt might end with TLS handshake errors.
certbot –preferred-challenges http
Reverse Proxy for Exchange
Create a new Apache configuration file for Exchange’s new reverse proxy:
<VirtualHost *:443> ServerName mail.example.com ServerAlias autodiscover.example.com ServerAdmin [email protected] ErrorLog /var/log/apache2/error.log CustomLog /var/log/apache2/access.log combined Header always set X-Frame-Options SAMEORIGIN Header set Server Apache Header unset X-AspNet-Version Header unset X-OWA-Version Header unset X-Powered-By RequestHeader unset Expect early SetEnvIf User-Agent ".*MSIE.*" value BrowserMSIE Header unset WWW-Authenticate Header add WWW-Authenticate "Basic realm=mail.example.com" ProxyRequests Off ProxyPreserveHost On SSLProxyEngine on SSLProxyVerify none SSLProxyCheckPeerCN off SSLProxyCheckPeerName off SSLProxyCheckPeerExpire off #longer connection timeout to prevent activesync errors ProxyPass / https://exchange2016.example.local/ connectiontimeout=600 ProxyPassReverse / https://exchange2016.example.local/ <Directory /Microsoft-Server-ActiveSync> #attachment/activesync bugfix SSLRenegBufferSize 31457280 </Directory> #charset e.g. for german special chars AddDefaultCharset ISO-8859-1 DocumentRoot /var/www/html <Directory /> Order deny,allow Deny from all </Directory> <Directory /var/www/html> DirectoryIndex index.php index.html Options -Indexes +FollowSymLinks Order allow,deny Allow from all </Directory> <Proxy *> SetEnv proxy-nokeepalive 1 SetEnv force-proxy-request-1.0 1 Order deny,allow Allow from all </Proxy> SSLEngine on BrowserMatch "MSIE [2-6]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0 # MSIE 7 and newer should be able to use keepalive BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown </VirtualHost>
We only need this reverse proxy on port 443, not 80.
Make sure you really use local server names (e.g. for ProxyPass) which are always resolved to the server’s local IP (not the firewall ot public IP)! If not sure, you can also use IP addresses, SSL certs are not checked at this point. Otherwise you might experience senseless loopbacks.
Enable the necessary Apache modules:
a2enmod headers a2enmod rewrite a2enmod proxy_http a2enmod ssl
Enable the new virtual host (a2ensite exchange).
Re-run certbot, it should append lines to the file, e.g. “SSLCertificateFile”, keyfile, chainfile etc.
Run “service apache2 reload” and check for errors.
Change your site’s URLs to https://www.example.com within the admin area.
In Exchange’s virtual directories, make sure you have basic authentification enabled (for OWA, EWS, …). Apache is not able to use NTLM mechanism, so we need this workaround. You can enable it either via Exchange Administrative Center -> Server -> Virtual Directories, or IIS, or Exchange Management Shell.
Activate the new rule you created before, so port 443 is forwarded to your webserver instead of Exchange directly.
Use Microsoft’s Analyzer to test Exchange connectivity features you need, e.g. Autodiscover, ActiveSync (e.g. mobile phones), Exchange Web Services (EWS) etc.
Check your Apache logfiles for connection errors (500, timeouts, …).
Check if your websites are loading fine via HTTPS URL in every browser. Parts of your sites might still contain HTTP links to scripts or graphics; in this case change the link to the more generic “//” to avoid browser warnings.
Create a cronjob similar to this one:
0 0 1 * * /usr/bin/certbot renew --preferred-challenges http >> /var/log/letsencrypt-renew.log #(HTTP option only for e.g. Cloudflare)
Because your Exchange Server also needs the certificate, but cannot request it itself any more, publish it on your webserver. Exchange will it download later for further processing.
#!/bin/bash PW=mypw SHARE=/var/www/html/other CERTPATH=/etc/letsencrypt/live MAINDOMAIN=example.com #the first domain name letsencrypt uses (main CN) #conversion for exchange openssl pkcs12 -export -in $CERTPATH/$MAINDOMAIN/cert.pem -inkey $CERTPATH/$MAINDOMAIN/privkey.pem -out $SHARE/exch.p12 -password pass:$PW
Also create a cronjob for it, which runs a few minutes after certbot.
Create a PowerShell script which downloads the certificate from your webserver and imports it into Exchange Server:
$CertPath="c:\letsencrypt\exch.p12" $ImportPassword="mypw" Add-PSSnapin *exchange* -ea 0 wget http://www/other/exch.p12 -OutFile $CertPath $ImportPassword = ConvertTo-SecureString $ImportPassword -AsPlainText -Force Import-ExchangeCertificate -FileName $CertPath -FriendlyName "example.com" -Password $ImportPassword -PrivateKeyExportable:$true | Enable-ExchangeCertificate -Services "SMTP, IMAP, POP, IIS" –force
Also create a scheduled task for it to make it run e.g. twice a week.
Finally, you should have all your websites accessible via HTTP and HTTPS, and Exchange Server including OWA, ActiveSync etc. should work besides.