Skip to main content

NGINX / Security

NGINX LDAP Authentication: Complete Module Setup Guide

by ,


We have by far the largest RPM repository with NGINX module packages and VMODs for Varnish. If you want to install NGINX, Varnish, and lots of useful performance/security software with smooth yum upgrades for production use, this is the repository for you.
Active subscription is required.

What Is NGINX LDAP Authentication?

NGINX does not include built-in LDAP authentication support, unlike Apache’s mod_authnz_ldap. However, with the nginx-auth-ldap dynamic module, you can authenticate users against one or more LDAP directories — including Microsoft Active Directory — directly within NGINX.

This approach eliminates the need for a separate authentication proxy or daemon. NGINX queries the LDAP server during the access phase, prompts for HTTP Basic credentials, and either grants or denies access based on your authorization rules.

In this guide, you will learn how to install the module from a pre-built package, configure it for common LDAP and Active Directory setups, enable TLS encryption, tune caching and connection pooling for production, and troubleshoot the most frequent issues.

Why Use NGINX LDAP Authentication?

Many organizations already maintain user directories in LDAP or Active Directory. Adding NGINX LDAP authentication to your infrastructure provides several advantages:

  • Centralized user management — add or remove access by updating your directory, not individual NGINX configs
  • No application changes required — protect any backend (static files, proxied applications, APIs) without modifying application code
  • Multiple server failover — configure primary and secondary LDAP servers for high availability
  • Granular access control — restrict access by user DN, group membership, or any valid LDAP filter

NGINX LDAP authentication is especially useful for protecting internal tools, admin panels, staging environments, and development resources behind your existing corporate directory. For token-based alternatives, see our guides on NGINX JWT authentication and NGINX TOTP two-factor authentication.

Installation

The easiest way to install the NGINX LDAP authentication module is through pre-built packages from the GetPageSpeed repository. This avoids compiling NGINX from source entirely.

On CentOS/RHEL 8+, AlmaLinux, Rocky Linux, and Fedora:

sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-auth-ldap

On CentOS/RHEL 7 and Amazon Linux 2:

sudo yum install https://extras.getpagespeed.com/release-latest.rpm
sudo yum install nginx-module-auth-ldap

On Ubuntu and Debian, set up our APT repository and then:

sudo apt-get install nginx-module-auth-ldap

After installing RPM packages, load the module by adding the following line at the top of your /etc/nginx/nginx.conf, before the http block:

load_module modules/ngx_http_auth_ldap_module.so;

This isn’t required on Debian or Ubuntu, as their packages automatically enable the module upon installation.

Verify that the module loaded correctly:

nginx -t

You should see:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Dependencies

The module links against libldap and liblber from the OpenLDAP client libraries. These are pulled in automatically when you install the package. For LDAPS certificate verification, you also need OpenSSL 1.0.2 or later — every supported distribution meets this requirement.

How It Works

The module operates in NGINX’s access phase. When a request reaches a protected location, the module performs the following steps:

  1. Credential prompt — NGINX returns a 401 Unauthorized response with a WWW-Authenticate: Basic header. The browser displays a login dialog.
  2. LDAP search — the module binds to the LDAP server using the configured binddn credentials (a service account), then searches for the user by matching the submitted username against the attribute specified in the LDAP URL (for example, uid or sAMAccountName).
  3. User bind — if the search finds a matching entry, the module attempts to bind as that user with the submitted password. A successful bind confirms the password is correct.
  4. Authorization check — the module evaluates require rules. Depending on your configuration, it checks whether the user is any valid user, a specific user DN, or a member of a required group.
  5. Access granted or denied — if all checks pass, the request proceeds to the content handler. Otherwise, NGINX returns 401 Unauthorized.

The module maintains persistent connections to the LDAP server, which means it does not open a new TCP connection for every request. You control the connection pool size with the connections directive.

Basic Configuration

LDAP server definitions go in the http block. You then reference them in server or location blocks to protect specific areas.

Here is a minimal working configuration:

http {
    ldap_server my_ldap {
        url "ldap://ldap.example.com/dc=example,dc=com?uid?sub?(objectClass=inetOrgPerson)";
        binddn "cn=readonly,dc=example,dc=com";
        binddn_passwd "ReadOnlyPassword";
        require valid_user;
        connections 5;
    }

    server {
        listen 80;
        server_name intranet.example.com;

        location / {
            auth_ldap "Restricted Area";
            auth_ldap_servers my_ldap;

            root /var/www/intranet;
            index index.html;
        }
    }
}

The auth_ldap directive sets the HTTP Basic authentication realm — the text shown in the browser’s login dialog. The auth_ldap_servers directive specifies which LDAP server definition to use for authentication.

Important: The connections directive is required in every ldap_server block. Without it, the module will silently allow all requests through without performing any authentication. See the troubleshooting section for details.

Understanding the LDAP URL

The url directive follows the standard LDAP URL format defined in RFC 4516:

ldap://host:port/base_dn?attribute?scope?(filter)

Each component controls how the module searches for users:

Component Example Purpose
Protocol ldap:// or ldaps:// Plain LDAP (port 389) or LDAP over TLS (port 636)
Host:Port ldap.example.com:389 LDAP server address
Base DN dc=example,dc=com Starting point for the search
Attribute uid Attribute to match against the submitted username
Scope sub Search scope: base, one, or sub (subtree)
Filter (objectClass=inetOrgPerson) Additional LDAP filter for matching entries

For Active Directory, you typically use sAMAccountName as the attribute and (objectClass=person) as the filter.

Disabling Authentication for Specific Locations

Use auth_ldap off to exclude certain paths from authentication:

server {
    listen 80;
    server_name intranet.example.com;

    # Protect everything by default
    auth_ldap "Restricted Area";
    auth_ldap_servers my_ldap;

    location / {
        root /var/www/intranet;
        index index.html;
    }

    # Health check endpoint — no authentication
    location = /health {
        auth_ldap off;
        return 200 "OK\n";
    }
}

Active Directory Configuration

Active Directory is the most common LDAP directory in enterprise environments. Here is a production-ready configuration for authenticating against AD:

ldap_server active_directory {
    url "ldap://dc1.corp.example.com:389/DC=corp,DC=example,DC=com?sAMAccountName?sub?(objectClass=person)";

    # Service account for directory searches
    binddn "CN=NGINX Service,OU=Service Accounts,DC=corp,DC=example,DC=com";
    binddn_passwd "StrongServicePassword";

    # Group membership settings
    group_attribute member;
    group_attribute_is_dn on;

    # Allow access if the user belongs to ANY of these groups
    satisfy any;
    require group "CN=Web Admins,OU=Security Groups,DC=corp,DC=example,DC=com";
    require group "CN=Developers,OU=Security Groups,DC=corp,DC=example,DC=com";

    # Connection tuning
    connections 10;
    max_down_retries 3;
    connect_timeout 5s;
    bind_timeout 5s;
    request_timeout 10s;

    # Disable LDAP referrals (recommended for AD)
    referral off;
}

Active Directory Tips

Use sAMAccountName for the search attribute. This is the traditional Windows logon name (e.g., jsmith). Alternatively, use userPrincipalName if your users log in with their email-style UPN (e.g., jsmith@corp.example.com).

Disable referrals. Active Directory often returns referral responses when querying the Global Catalog or across domain boundaries. These referrals cause delays and authentication failures. Set referral off to prevent the module from following them.

Use a dedicated service account. Create a service account with read-only access to the directory. Grant only the permissions needed to search for users and read group memberships. Never use a domain administrator account.

Set group_attribute_is_dn on when using member as the group attribute. In Active Directory, the member attribute stores full distinguished names, not plain usernames.

Authorization Rules

The require directive controls who gains access after successful authentication. You can combine multiple rules with the satisfy directive.

Require Any Valid User

The simplest rule — any user who can successfully bind to the LDAP server is granted access:

ldap_server my_ldap {
    url "ldap://ldap.example.com/dc=example,dc=com?uid?sub?(objectClass=person)";
    binddn "cn=readonly,dc=example,dc=com";
    binddn_passwd "secret";
    require valid_user;
    connections 5;
}

Require Specific Users

Restrict access to specific user DNs:

ldap_server my_ldap {
    url "ldap://ldap.example.com/dc=example,dc=com?uid?sub?(objectClass=person)";
    binddn "cn=readonly,dc=example,dc=com";
    binddn_passwd "secret";
    satisfy any;
    require user "cn=alice,ou=users,dc=example,dc=com";
    require user "cn=bob,ou=users,dc=example,dc=com";
    connections 5;
}

Require Group Membership

Restrict access to members of specific LDAP groups:

ldap_server my_ldap {
    url "ldap://ldap.example.com/dc=example,dc=com?uid?sub?(objectClass=person)";
    binddn "cn=readonly,dc=example,dc=com";
    binddn_passwd "secret";
    group_attribute uniqueMember;
    group_attribute_is_dn on;
    require group "cn=admins,ou=groups,dc=example,dc=com";
    connections 5;
}

Combining Rules with satisfy

The satisfy directive controls how multiple require rules interact:

  • satisfy any (default) — the user must match at least one require rule
  • satisfy all — the user must match every require rule

For example, to require that a user is both a specific user AND a member of a group:

ldap_server strict_auth {
    url "ldap://ldap.example.com/dc=example,dc=com?uid?sub?(objectClass=person)";
    binddn "cn=readonly,dc=example,dc=com";
    binddn_passwd "secret";
    group_attribute uniqueMember;
    group_attribute_is_dn on;
    satisfy all;
    require user "cn=alice,ou=users,dc=example,dc=com";
    require group "cn=admins,ou=groups,dc=example,dc=com";
    connections 5;
}

LDAP Over TLS (LDAPS)

For production deployments, always encrypt LDAP connections using TLS. There are two approaches:

LDAPS (Port 636)

Use the ldaps:// scheme to establish a TLS connection from the start:

ldap_server secure_ldap {
    url "ldaps://ldap.example.com:636/dc=example,dc=com?uid?sub?(objectClass=inetOrgPerson)";
    binddn "cn=readonly,dc=example,dc=com";
    binddn_passwd "ReadOnlyPassword";

    # Verify the LDAP server's certificate
    ssl_check_cert on;
    ssl_ca_file /etc/pki/tls/certs/ca-bundle.crt;

    require valid_user;
    connections 5;
}

Certificate Verification

Enable ssl_check_cert on in production to prevent man-in-the-middle attacks. You must provide the CA certificate that signed the LDAP server’s certificate:

Directive Purpose
ssl_check_cert on Enable certificate verification (requires OpenSSL 1.0.2+)
ssl_ca_file Path to a CA certificate bundle file
ssl_ca_dir Path to a directory containing CA certificates

On RHEL-based systems, the system CA bundle is typically located at /etc/pki/tls/certs/ca-bundle.crt. On Debian/Ubuntu, use /etc/ssl/certs/ca-certificates.crt.

If your LDAP server uses a self-signed or internal CA certificate, place the CA certificate file on the NGINX server and reference it with ssl_ca_file.

Multi-Server Failover

For high availability, define multiple LDAP servers and reference them all in the location block. NGINX queries each server in order. If the first server is unreachable, authentication falls through to the next:

ldap_server ldap_primary {
    url "ldap://ldap1.example.com/dc=example,dc=com?uid?sub?(objectClass=person)";
    binddn "cn=readonly,dc=example,dc=com";
    binddn_passwd "secret";
    require valid_user;
    max_down_retries 2;
    connections 5;
    connect_timeout 3s;
}

ldap_server ldap_secondary {
    url "ldap://ldap2.example.com/dc=example,dc=com?uid?sub?(objectClass=person)";
    binddn "cn=readonly,dc=example,dc=com";
    binddn_passwd "secret";
    require valid_user;
    max_down_retries 2;
    connections 5;
    connect_timeout 3s;
}

server {
    listen 80;
    server_name intranet.example.com;

    location / {
        auth_ldap "Restricted Area";
        auth_ldap_servers ldap_primary;
        auth_ldap_servers ldap_secondary;

        root /var/www/intranet;
        index index.html;
    }
}

Note that each auth_ldap_servers directive references a single server by its alias name. Use multiple auth_ldap_servers directives to add failover servers.

Authentication Caching

By default, the module queries the LDAP server for every request. This can place significant load on the directory server, especially for high-traffic applications. Enable caching to store authentication results in memory:

http {
    # Enable LDAP auth result caching
    auth_ldap_cache_enabled on;
    auth_ldap_cache_expiration_time 30s;
    auth_ldap_cache_size 200;

    ldap_server my_ldap {
        # ... server configuration ...
    }
}

Cache Directives

Directive Default Description
auth_ldap_cache_enabled off Enable or disable authentication result caching
auth_ldap_cache_expiration_time 10s How long cached results remain valid (minimum: 1s)
auth_ldap_cache_size 100 Maximum number of cached entries (minimum: 100)

Cache Sizing Guidelines

Choose your cache size based on the number of concurrent authenticated users. A cache size of 200 handles most small-to-medium deployments. For larger environments with hundreds of simultaneous users, increase the value accordingly.

Set the expiration time based on your security requirements. A shorter expiration (10–30 seconds) ensures that password changes and account lockouts take effect quickly. A longer expiration (5–10 minutes) reduces LDAP server load but delays propagation of credential changes.

Complete Directive Reference

Top-Level Directives (http block)

Directive Context Default Description
ldap_server http Define a named LDAP server configuration block
auth_ldap_cache_enabled http off Enable authentication result caching
auth_ldap_cache_expiration_time http 10s Cache entry lifetime (minimum: 1s)
auth_ldap_cache_size http 100 Maximum cached entries (minimum: 100)
auth_ldap_servers_size http 7 Maximum number of LDAP server definitions

Location-Level Directives

Directive Context Default Description
auth_ldap http, server, location, limit_except Set the realm string for Basic auth, or off to disable
auth_ldap_servers http, server, location, limit_except Reference an LDAP server by alias name (repeatable)

Directives Inside ldap_server { } Block

Directive Default Description
url LDAP URL (ldap:// or ldaps://) with search base, attribute, scope, and filter
binddn DN of the service account used for searching the directory
binddn_passwd Password for the service account
group_attribute LDAP attribute that stores group membership (e.g., member, uniqueMember)
group_attribute_is_dn off Whether the group attribute contains full DNs (on) or plain usernames (off)
require Authorization rule: valid_user, user "DN", or group "DN" (repeatable)
satisfy any How multiple require rules combine: all or any
connections Number of persistent connections to maintain to this LDAP server (required)
max_down_retries 0 Number of reconnection attempts when the LDAP server is unreachable
connect_timeout 10s Timeout for establishing a connection to the LDAP server
reconnect_timeout 10s Delay before attempting to reconnect after a connection failure
bind_timeout 5s Timeout for LDAP bind operations
request_timeout 10s Timeout for LDAP search and compare operations
referral on Whether to follow LDAP referrals (disable for Active Directory)
ssl_check_cert off Verify the LDAP server’s TLS certificate (requires OpenSSL 1.0.2+)
ssl_ca_file Path to a CA certificate bundle file for verification
ssl_ca_dir Path to a directory of CA certificates for verification

Performance Considerations

Connection Pooling

The connections directive controls how many persistent TCP connections the module maintains to each LDAP server. Each NGINX worker process creates its own connection pool, so the total number of connections is connections × worker_processes.

For example, with connections 5 and 4 worker processes, NGINX maintains up to 20 connections to the LDAP server. Size this based on your expected authentication rate:

ldap_server my_ldap {
    # ...
    connections 5;  # Per worker process
}

Timeout Tuning

Aggressive timeouts prevent NGINX workers from blocking when an LDAP server becomes slow or unresponsive:

ldap_server my_ldap {
    # ...
    connect_timeout 3s;   # Fast failure on unreachable servers
    bind_timeout 3s;      # Fast failure on slow binds
    request_timeout 5s;   # Allow slightly more time for searches
    reconnect_timeout 5s; # Wait before retrying a failed connection
}

Worker Process Impact

The LDAP module performs synchronous LDAP operations within the NGINX worker process. While an LDAP query is in progress, that worker cannot handle other requests. Therefore:

  • Keep LDAP servers on low-latency networks (ideally the same data center)
  • Set aggressive timeouts to prevent long-running LDAP operations from blocking workers
  • Enable caching to reduce the number of LDAP queries
  • Monitor NGINX connection queues for signs of worker starvation

Security Best Practices

Encrypt All LDAP Traffic

Always use LDAPS in production. Unencrypted LDAP transmits credentials in plain text, making them vulnerable to network sniffing:

ldap_server secure_ldap {
    url "ldaps://ldap.example.com:636/dc=example,dc=com?uid?sub?(objectClass=person)";
    ssl_check_cert on;
    ssl_ca_file /etc/pki/tls/certs/ca-bundle.crt;
    # ...
}

Protect Bind Credentials

The binddn_passwd value appears in plain text in your NGINX configuration file. Restrict access to the configuration:

sudo chmod 600 /etc/nginx/conf.d/ldap.conf
sudo chown root:root /etc/nginx/conf.d/ldap.conf

Alternatively, use the include directive to store LDAP credentials in a separate, restricted file:

ldap_server my_ldap {
    url "ldap://ldap.example.com/dc=example,dc=com?uid?sub?(objectClass=person)";
    include /etc/nginx/ldap-credentials.conf;
    require valid_user;
    connections 5;
}

Where /etc/nginx/ldap-credentials.conf contains:

binddn "cn=readonly,dc=example,dc=com";
binddn_passwd "ReadOnlyPassword";

Use a Least-Privilege Service Account

The bind DN account only needs permissions to:

  • Search for user entries in the configured base DN
  • Read group membership attributes

It does NOT need write access, admin privileges, or the ability to modify passwords.

Combine with IP Restrictions

For sensitive resources, layer LDAP authentication with IP-based access control:

location /admin {
    allow 10.0.0.0/8;
    deny all;

    auth_ldap "Admin Area";
    auth_ldap_servers active_directory;

    proxy_pass http://admin-backend;
}

Both the IP check and LDAP authentication must pass for the request to proceed.

Rate Limiting Against Brute Force

Protect the LDAP server from brute-force password attacks by adding rate limiting:

http {
    limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=5r/s;

    server {
        location /protected {
            limit_req zone=auth_limit burst=10 nodelay;

            auth_ldap "Protected";
            auth_ldap_servers my_ldap;

            proxy_pass http://backend;
        }
    }
}

Troubleshooting

connections Directive Missing — Module Allows All Requests

This is the most critical misconfiguration. If you omit the connections directive from a ldap_server block, the module will silently allow all requests through without performing any authentication. No error messages appear in the logs — the module simply grants access to everyone, including unauthenticated requests.

This behavior was confirmed through runtime testing: without connections, requests with no credentials, wrong passwords, and unauthorized users all receive HTTP 200 responses.

Solution: Always include the connections directive in every ldap_server block:

ldap_server my_ldap {
    url "ldap://ldap.example.com/dc=example,dc=com?uid?sub?(objectClass=person)";
    binddn "cn=readonly,dc=example,dc=com";
    binddn_passwd "secret";
    require valid_user;
    connections 5;  # Required — without this, authentication is bypassed
}

A value of 5 is suitable for most deployments. Increase it for high-traffic environments.

“host not found in LDAP hostname”

This error appears during nginx -t when NGINX cannot resolve the hostname specified in the LDAP URL:

nginx: [emerg] http_auth_ldap: host not found in LDAP hostname "ldap.example.com"

Solution: Verify DNS resolution on the NGINX server:

dig ldap.example.com +short

If DNS is unreliable, add the LDAP server to /etc/hosts as a fallback.

“Could not connect” Errors

Repeated http_auth_ldap: Could not connect messages in the error log indicate that NGINX cannot establish a TCP connection to the LDAP server.

Common causes:
– Firewall blocking LDAP ports (389/636)
– LDAP server is down
– Incorrect hostname or port in the url directive

Debugging steps:

# Test TCP connectivity
nc -zv ldap.example.com 389

# Test LDAP search directly
ldapsearch -x -H ldap://ldap.example.com -b "dc=example,dc=com" -D "cn=readonly,dc=example,dc=com" -W "(uid=testuser)"

Authentication Succeeds But Access Denied

If users can authenticate (their password is accepted) but are still denied access, the issue is usually in the require rules:

  • Verify that the user’s DN matches the format in require user
  • Verify that the group DN is correct and the user is actually a member
  • Check whether satisfy all requires matching ALL rules when you intended satisfy any

Enable debug logging to see the exact LDAP operations:

error_log /var/log/nginx/error.log debug;

Then search the log for http_auth_ldap entries to trace the authentication flow.

Connection Timeouts Under Load

If authentication becomes slow or times out during peak traffic, the LDAP connection pool may be exhausted:

  • Increase the connections value
  • Enable caching with auth_ldap_cache_enabled on
  • Reduce timeout values so failed connections are recycled faster
  • Check LDAP server performance metrics

LDAP Referral Errors

Active Directory environments commonly produce referral-related errors. Set referral off in your LDAP server configuration to prevent these:

ldap_server active_directory {
    # ...
    referral off;
}

Comparison with Other NGINX LDAP Authentication Approaches

The auth-ldap module is not the only way to add NGINX LDAP authentication. Here is how it compares with alternative approaches:

Approach Pros Cons
auth-ldap module (this guide) Native NGINX module, no external processes, simple configuration Synchronous LDAP operations, must compile or install as dynamic module
auth_request + LDAP daemon Asynchronous, does not block NGINX workers Requires running a separate daemon process, more complex setup
OAuth2 Proxy / Keycloak Modern SSO, supports OIDC/SAML, token-based Significant infrastructure overhead, over-engineered for simple LDAP use cases

For straightforward NGINX LDAP authentication needs — especially protecting internal tools, admin panels, or staging environments — the auth-ldap module is the most direct solution. If your environment requires more advanced authentication, consider NGINX JWT authentication for API-centric architectures or NGINX TOTP authentication for adding two-factor security.

Conclusion

The NGINX auth-ldap module provides native LDAP authentication that integrates directly with your existing directory services. With pre-built packages from the GetPageSpeed repository, you can install and configure it in minutes, without compiling NGINX from source.

For production deployments, remember to:

  • Always include the connections directive in every ldap_server block
  • Use LDAPS with certificate verification
  • Enable authentication caching to reduce LDAP server load
  • Configure connection pooling and timeouts for your expected traffic
  • Use a least-privilege service account for directory searches
  • Add rate limiting to protect against brute-force attacks

The module source code is available on GitHub.

D

Danila Vershinin

Founder & Lead Engineer

NGINX configuration and optimizationLinux system administrationWeb performance engineering

10+ years NGINX experience • Maintainer of GetPageSpeed RPM repository • Contributor to open-source NGINX modules

Leave a Reply

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

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.