Post

How to run multiple web services behind one public IP address

With nginx, a domain name, and Let's Encrypt, all internal and external-facing web applications can use HTTPS — even on a home network

How to run multiple web services behind one public IP address

One of the most popular use cases for nginx (pronounced Engine X) is to to act as a reverse proxy that takes requests from web clients and proxies them to application webservers. You can configure your firewall/router to forward TCP ports 80 (for HTTP) and 443 (for HTTPS) to a server running nginx, and nginx be configured to proxy incoming web requests to the correct webserver based on the hostname in the web request. Each application will also use nginx as its webserver. Let’s Encrypt TLS certificates can provide certificates that protect traffic to the edge webserver and between the edge webserver and the internal webservers, and between internal clients and the internal webservers.

Let’s Encrypt

Let’s Encrypt is a Certificate Authority (CA) that issues free TLS certificates. It uses the ACME protocol to verify control of a domain before issuing a certificate. There are two methods of verification: the HTTP challenge and the DNS challenge.

In the ACME HTTP challenge, the ACME client temporally places a file at a path specified by the ACME server under /.well-known/acme-challenge/. The ACME server then checks for that file and issues the certificate if it exists.

In the ACME DNS challenge, the ACME client temporally adds a TXT DNS record to the domain at _acme-challenge, waits a few seconds for the DNS change to propagate, then the ACME server checks if that record exists before issuing the certificate.

In this guide, we’ll use certbot as the ACME client to verify domains on the edge webserver using DNS, and via HTTP on the application webservers. If a web application needs to be public facing, we’ll configure the edge webserver to proxy all web traffic for that domain to the application server. But, if a web a web application is for internal use only, we’ll configure the edge webserver to only forward traffic for the ACME HTTP verification path and return HTTP 404 Not Found for any other path. This architecture has a couple of key advantages.

  • Credentials for modifying DNS records are only located on one webserver, rather than every webserver
  • internal only applications can use the HTTP challenge without the application being publicly exposed

DNS configuration

To make this architecture work, you’ll need:

  • A registered domain name pointed to DNS nameservers supported by certbot
  • A DNS server on your local network that hosts non-authoritative DNS zones that point to internal IP addresses
    • Many firewalls have the ability to configure an internal DNS server
    • Alternatively, the hostnames could be added to the hosts file of the edge webserver
    • A static public IP address or a dynamic DNS hostname pointing to a dynamic public IP address
      • Some firewalls/router manufacturers offer their own dynamic DNS service for free

Configure your hostnames for all web applications in both internal and external DNS zones, even if they are internal-only applications.

In this guide we’ll use example.net as our domain.

External DNS

Configure a DNS record for web.example.net that points to the public address of your edge webserver

  • Use an A record if you have an IPv4 public IP address
  • Use an AAAA record if you have an IPv6 public IP address
  • Use a CNAME record if you are using a dynamic DNS hostname

Next, configure a CNAME record for each web application hostname you’ll use, and point it to web.example.net. This way, if you ever need to change the public IP address for the webserver, you only need to do it for web.example.net.

Internal DNS

Configure your internal DNS server or hosts file on your webserver so that the same hostnames configured in external DNS point to each individual internal IP address of the server that is hosting the application. This way, the edge webserver will proxy requests to the correct internal systems, instead of to itself.

Install certbot

Install certbot on all webservers. Instructions for installing certbot can be found on the project’s website.

This guide will show how to install certbot on a Debian or Ubuntu server using snapd.

1
2
3
4
sudo apt update
sudo apt install snapd
sudo snap install snapd
sudo snap install --classic certbot

Configure the edge webserver to proxy traffic to internal webservers

Create a nginx configuration file for each hostname. On Debian or Ubuntu servers, for example run:

1
sudo nano /etc/nginx/sites-available/internal.example.net

Other Linux distributions may store nginx configuration files in /etx/nginx/conf.d/.

Internal-only applications

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
    listen 80;
    listen [::]:80;
    server_name internal.example.net;

    location /.well-known/acme-challenge/ {
        proxy_pass http://internal.example.net;
        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;
    }

    location / {
        return 404;
    }
}

External-facing applications

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
    listen 80;
    listen [::]:80;
    server_name external.example.net;

    location / {
        proxy_pass http://external.example.net;
        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;
    }
}

For external-facing applications, you add the same nginx configuration options that you do in the application’s web server configuration (e,g, client_max_body_size).

Enable the configuration

On Debian or Ubuntu systems, you must add a symlink for each configuration file for it to apply.

1
2
sudo ln -s /etc/nginx/sites-available/internal.example.net /etc/nginx/sites-enabled/internal.example.net
udo ln -s /etc/nginx/sites-available/external.example.net /etc/nginx/sites-enabled/external.example.net

Restart the server to apply the configuration changes.

1
sudo service nginx restart

Obtain TLS certificates on the edge webserver

Use a certbot DNS plugin to obtain certificates for the edge webserver using the DNS challenge.

Configure nginx to use Let’s Encrypt certificates

On the external webserver, run:

1
sudo certbot -d internal.example.com -d external.example.com --nginx

Use as many -d arguments as needed for each domain.

And confirm that you want to use the existing certificates that you obtained with the last command.

Run the same command on each application server. The HTTP challenge request should be successfully routed through the edge webserver and pass.

Update the edge web server to proxy using HTTPS

Once an application server has successfully passed the HTTP challenge and obtained a TLS certificate, change the corresponding nginx configuration on the edge web server for that application to use https instead of http in the proxy_pass option and restart or reload nginx. Otherwise, a redirect loop will occur, resulting in a Too many redirects error.

Enhance security with network segmentation

If your networking equipment supports network segmentation (i.e., VLANs), you can enhance security by placing each of the application servers in separate VLANs/zones, then place the edge web server in its own DMZ/zone, and add firewall rules to allow it to communicate with the upstream webservers. That way. if a web application is compromised, the attackers cannot move directly to another application or your internal network.

This post is licensed under CC BY 4.0 by the author.