Nginx Proxy Manager is a reverse-proxy manager which allows for… reverse proxies. Go figure. This is most commonly used for binding nice service names to services on other ports or internal to a docker network; for example, https://gitea.my.domain is proxied to a docker container not otherwise reachable.

Setting up a proxy

  • write setting up a proxy section

Using reverse proxy sites

For the proxy to work, you’ll have to get to the IP address of the proxy site. This means making a DNS request to proxysite.proxyhost.com — which means you need to have a DNS record for that host. Typically, it is inconvenient to do this for all proxied subdomains, so you will want to make a wildcard record.

If you self-host your DNS, see either Custom Wildcard Records or Custom Wildcard Records.

If you use Amazon Route53, you can simply make a *.my.domain A record and point it to the public elastic IP address.

SSL certificate management behind a firewall

If you run nginx-proxy-manager behind a firewall such that the open internet cannot access it, getting SSL certificates isn’t going to work by default. Instead, you have to use LetsEncrypt’s DNS-01 challenge. You will need to be able to update subdomains of your domain via API for this to work. I’m using AWS Route53 as my provider.

Account provisioning

First, you’ll need to set up an account for LetsEncrypt to use to update domains. You will need the ID of your hosted zone from Route 53; you can find it in the hosted zone you want to update, under the “Hosted zone details” dropdown at the top of the page.

  1. Go to IAM Policies
  2. Click Create Policy
  3. In the Permissions dialog, select JSON
  4. Set the policies as follows:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "route53:GetChange"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "route53:ChangeResourceRecordSets"
            ],
            "Resource": [
                "arn:aws:route53:::hostedzone/<your hosted zone ID here>"
            ]
        }
    ]
}
  1. Give the policy a name you can easily identify later (I used letsencrypt-dns01-policy)
  2. Click Create Policy

Next, create a user group with this policy attached.

  1. Go to IAM IAM user groups
  2. Click Create User Group
  3. Give the group a name you’ll recognize later
  4. Under the “Attach permissions policies”, set “Filter by Type” to “Customer Managed”
  5. Select and add the permissions policy you created previously

Now, create the user.

  1. Go to IAM IAM Users
  2. Click Create User
  3. Give the user a name you’ll recognize later
  4. Click Next
  5. Select the group you just created, and click Next, then Create User

Finally, you’ll need to get credentials for that user.

  1. Select the user you just created
  2. Go to Security Credentials
  3. Find Access Keys, and select Create Access Key
  4. Select Other
  5. Give the key a recognizable name
  6. Click Create
  7. Note down both the access key and secret access key. You’ll need them soon and won’t be able to see them after clicking Done.

Configuring DNS-01 challenge

To configure the DNS challenge:

  1. Go to Nginx-proxy-manager Certificates
  2. Add a new certificate
  3. Set the URL to *.your.domain.com (note the leading *. to certify subdomains!)
  4. Select Route 53 (Amazon) for the provider
  5. In the credentials file content box, update the aws_access_key_id with the access key from IAM
  6. In the credentials file content box, update the aws_secret_access_key with the secret key from IAM

Bug

Do NOT enter anything in the propagation seconds box! It’s currently broken. However, if you leave it alone, whatever the default option is seems to work. See https://github.com/NginxProxyManager/nginx-proxy-manager/issues/4702 .

  1. Click Save
  2. Be patient! This step may take up to 10 minutes as LetsEncrypt adds a DNS record, then has to wait for it to propagate throughout the DNS zone before it can verify your ownership of the domain.

If all goes well, the dialog should close itself shortly and you’ll have the certificate in the list.

Access lists

NPM can also selectively allow/block traffic to a service based on where it originates. This can be useful if you want to completely restrict access to a service even before someone gets the chance to log in.

  1. Go to the Access Lists tab
  2. Add a new access list (using Add Access List)
  3. Give it a name that you’ll use to select this control list when applying it to services
  4. Go to the Rules tab
  5. Add the rules you want to use (more on this shortly)
  6. Click Save

Now, to apply this control list to a service:

  1. Go to the Proxy Hosts menu
  2. Select (or create) the service to edit
  3. Under the Access List dropdown, select the list you want to use

Done.

I find it easiest to manage the access rules based on subnets, as I keep my network divided into separate subnets for each category of users (for example, my LAN is 192.168.30.0/24, while everything coming in from those I give VPN access to arrives from 192.168.33.0/24). So, to create a service which only I can access, I add one allow rule for 192.168.30.0/24. To create a “public” service (really, “available to those who I grant VPN access”), I additionally add the VPN subnet 192.168.33.0/24.

Docker networks

If you have multiple services which talk to each other using the reverse proxy, and which talk to each other on the same Docker host, you may also need to add the Docker networks to this allowlist, otherwise your services may be blocked by the proxy!