Select Page
This entry has been published on 2018-06-08 and may be out of date.

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.



New configurations


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>

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"

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

#charset e.g. for german special chars
AddDefaultCharset ISO-8859-1

DocumentRoot /var/www/html

<Directory />
    Order deny,allow
    Deny from all

<Directory /var/www/html>
    DirectoryIndex index.php index.html
    Options -Indexes +FollowSymLinks
    Order allow,deny
    Allow from all

<Proxy *>
        SetEnv proxy-nokeepalive 1
        SetEnv force-proxy-request-1.0 1
        Order deny,allow
        Allow from all

  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

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 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.


Refreshing certificates


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.


CERTPATH=/etc/letsencrypt/live #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:


Add-PSSnapin *exchange* -ea 0

wget http://www/other/exch.p12 -OutFile $CertPath

$ImportPassword = ConvertTo-SecureString $ImportPassword -AsPlainText -Force

Import-ExchangeCertificate -FileName $CertPath -FriendlyName "" -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.