How to setup NGINX reverse proxy for Microsoft Exchange

Introduction on NGINX

NGINX is a modern fast webserver which also can be used as an reverse proxy server. A proxy server is a go‑between or intermediary server that forwards requests for content from multiple clients to different servers across the Internet. A reverse proxy server is a type of proxy server that sits behind the firewall in a private network and directs client requests to the appropriate backend server. The reverse proxy server can also do TLS offloading. In this guide we will setup the TLS offloading with Let’s Encrypt.

Using a reverse proxy server with Microsoft Exchange has some challenges to overcome to get everything functional.

Installing Nginx

For this guide we will be using Ubuntu 20.04 with the Nginx version available in the apt repositories.

First install Nginx and required modules then enable it:

# Install Nginx
sudo apt install -y nginx

# Enable Nginx
sudo systemctl enable nginx

# Headers more - Required for Microsoft Exchange
sudo apt-get install -y libnginx-mod-http-headers-more-filter

Install Certbot and python module for Nginx:

# Install certbot and python module
sudo apt install -y certbot python3-certbot-nginx

Unlink the default site:

# Unlink the default site
unlink /etc/nginx/sites-enabled/default

Configure Nginx reverse proxy for Microsoft Exchange

Create the Nginx server block configuration:

sudo nano /etc/nginx/sites-available/mail.domain.tld.conf

Paste in the following info to be able to create an Let’s Encrypt certificate via Certbot:

server {
    listen 80;
    listen [::]:80;
    server_name $mail.domain.tld;

    location / {
        proxy_pass https://$exchange_server;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Enable the configuration:

# Link the conf
sudo ln -s /etc/nginx/sites-available/mail.domain.tld.conf /etc/nginx/sites-enabled/mail.domain.tld.conf

# Reload Nginx
sudo systemctl reload nginx

Run certbot to create the Let’s Encrypt certificate:

# Run certbot
sudo certbot

# Select the mail.domain.tld in the certbot menu
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: mail.domain.tld

# Follow the cerbot configuration and let certbot manage the Nginx configuration.

After running certbot to create the certificate via Let’s Encrypt we can paste in the following info and edit the domain names and server locations:

server {
        if ($host = $mail.domain.tld) {
        return 301 https://$host$request_uri;
        } # managed by Certbot

        listen 80;
        listen [::]:80;

        server_name $mail.domain.tld;
        return 404; # managed by Certbot

        ssl_verify_client       off;

}
server {

        listen [::]:443 ssl http2 ipv6only=on; # managed by Certbot
        listen 443 ssl http2; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/$mail.domain.tld/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/$mail.domain.tld/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

        server_name $mail.domain.tld;

        ssl_verify_client       off;

        location /                              { proxy_pass https://$exchange_server; }
        location /owa                           { proxy_pass https://$exchange_server/owa; }
        location /exchange                      { proxy_pass https://$exchange_server/exchange; }
        location /ews                           { proxy_pass https://$exchange_server/ews; }
        location /mapi                          { proxy_pass https://$exchange_server/mapi; }
        location /rpc                           { proxy_pass https://$exchange_server/rpc; }
        location /oab                           { proxy_pass https://$exchange_server/oab; }
        location /autodiscover                  { proxy_pass https://$exchange_server/autodiscover; }
        location /Microsoft-Server-ActiveSync   { proxy_pass https://$exchange_server/Microsoft-Server-ActiveSync; }
        location /ecp                           { proxy_pass https://$exchange_server/ecp; }

        proxy_pass_request_headers on;
        proxy_pass_header Date;
        proxy_pass_header Server;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        more_set_input_headers 'Authorization: $http_authorization';
        proxy_set_header Accept-Encoding "";
        more_set_headers -s 401 'WWW-Authenticate: Basic realm="$mail.domain.tld"';

        proxy_read_timeout 3600;

        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;

        access_log /var/log/nginx/$mail.domain.tld-access.log;
        error_log /var/log/nginx/$mail.domain.tld-error.log;

}

Verify the Nginx configuration and reload Nginx.

# Verify Nginx configuration
sudo nginx -t

# Reload Nginx configuration
sudo systemctl reload nginx

Conclusion

The Nginx reverse proxy is now ready to proxy your Microsoft Exchange Server traffic with TLS offloading via a Let’s Encrypt certificate. Including a working ActiveSync configuration so that all mail clients can connect to your Microsoft Exchange server including Outlook clients.

10 comments

  1. Thank you so much for this, it was exactly what I needed.
    One question though, it seems that my mail clients (outlook and mac mail) is unable to log in to the mail server. It works fine on my phone. Do you know what could be wrong? The error is unable to verify username and / or password.

    1. Hey Lars,

      Did you config this part?:

      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto https;
      more_set_input_headers ‘Authorization: $http_authorization’;
      proxy_set_header Accept-Encoding “”;
      more_set_headers -s 401 ‘WWW-Authenticate: Basic realm=”$mail.domain.tld”‘;

      Probably something related to the headers.

      1. Hello, having same problem. Mobile devices are just fine, but server did not accept user’s password. Any tips?

        nging’s log:

        2022/08/04 14:48:23 [crit] 3520#3520: *17 SSL_read() failed (SSL: error:0A000126:SSL routines::unexpected eof while reading) while reading response header from upstream, client: 1.2.3.4, server: mail1.mydomain.com, request: “RPC_IN_DATA /rpc/rpcproxy.dll?9a6b8a40-f45f-47d6-b6c9-1f58d5851863@mydomain.com:6004 HTTP/1.1”, upstream: “https://192.168.1.100:443/rpc/rpcproxy.dll?9a6b8a40-f45f-47d6-b6c9-1f58d5851863@mydomain.com:6004”, host: “mail1.mydomain.com”

  2. Guys, I am into the topic… trying to get my Outlook users to be able to communicate with Exchange Server thur an reverse proxy (nginx) but I am stuck with the basics… where should I update the settings?

    In the “Custom Nginx Configuration” for the site? or should I ad them somewhere else? should I update the settings like $mail.domain.tld to reflect my domain? etc etc…

    Thanks!

  3. Hi,
    thanks for taking the effort to write this, but…

    this is not SSL offloading as the connection from NGINX to Exchange is also SSL. This is called: SSL bridging and still requires certificates on the Exchange backend.
    Correct SSL offloading would be as follows: Client –> NGINX is SSL, and then Nginx to Exchange would be plain http. Otherwise there is no “offloading”, as the Exchange Server would also have the full burden of encrypting/decrypting the traffic.

    Also on my side, this does not work with current Outlook clients. It always loops, asking for credentials.

    If anyone has this fixed, please post it here.

    Same here with Exchange 2010 and Outlook 365.

  4. I am also having the same issue as John Ranger. OWA is working properly however, Outlook clients are repeatedly prompted for a password.
    If anyone has a fix, PLEAS post it.

Leave a Reply

Your email address will not be published. Required fields are marked *