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
Pre-Built Package (Recommended)
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:
- Credential prompt — NGINX returns a
401 Unauthorizedresponse with aWWW-Authenticate: Basicheader. The browser displays a login dialog. - LDAP search — the module binds to the LDAP server using the configured
binddncredentials (a service account), then searches for the user by matching the submitted username against the attribute specified in the LDAP URL (for example,uidorsAMAccountName). - 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.
- Authorization check — the module evaluates
requirerules. Depending on your configuration, it checks whether the user is any valid user, a specific user DN, or a member of a required group. - 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 onerequirerulesatisfy all— the user must match everyrequirerule
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 allrequires matching ALL rules when you intendedsatisfy 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
connectionsvalue - 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
connectionsdirective in everyldap_serverblock - 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.
