From c1adb1364371709ae6e05efb9a25161bdfa7c9f2 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 6 Jan 2026 23:43:31 +0530 Subject: [PATCH 1/6] feat(nginx): add wildcard htpasswd support for multisite --- nginx-proxy/nginx.tmpl | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/nginx-proxy/nginx.tmpl b/nginx-proxy/nginx.tmpl index 5ac62da..4b0134d 100644 --- a/nginx-proxy/nginx.tmpl +++ b/nginx-proxy/nginx.tmpl @@ -61,13 +61,45 @@ {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} include /etc/nginx/vhost.d/default_acl; {{ end }} - {{ else if (exists "/etc/nginx/htpasswd/default") }} + {{/* + Wildcard htpasswd support for WordPress Multisite. + Naming convention: _wildcard.domain.com applies to domain.com AND *.domain.com + Note: For multi-level TLDs (e.g., domain.co.uk), create specific htpasswd files. + */}} + {{ else }} + {{ $hostParts := split .Host "." }} + {{ $partsLen := len $hostParts }} + {{ if ge $partsLen 2 }} + {{/* Build base domain from last 2 parts: e.g., blog.domain.com -> domain.com */}} + {{ $lastIndex := sub $partsLen 1 }} + {{ $secondLastIndex := sub $partsLen 2 }} + {{ $baseDomain := printf "%s.%s" (index $hostParts $secondLastIndex) (index $hostParts $lastIndex) }} + {{ $wildcardHtpasswd := printf "/etc/nginx/htpasswd/_wildcard.%s" $baseDomain }} + {{ if (exists $wildcardHtpasswd) }} + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file {{ $wildcardHtpasswd }}; + {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} + include /etc/nginx/vhost.d/default_acl; + {{ end }} + {{ else if (exists "/etc/nginx/htpasswd/default") }} auth_basic "Restricted {{ .Host }}"; auth_basic_user_file /etc/nginx/htpasswd/default; - {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} + {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; - {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} + {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} include /etc/nginx/vhost.d/default_acl; + {{ end }} + {{ end }} + {{ else if (exists "/etc/nginx/htpasswd/default") }} + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file /etc/nginx/htpasswd/default; + {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} + include /etc/nginx/vhost.d/default_acl; + {{ end }} {{ end }} {{ end }} From dae55f7891d31b1ca728f42ec102d1bceff7ff37 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 6 Jan 2026 23:43:49 +0530 Subject: [PATCH 2/6] feat(readme): add comprehensive documentation for nginx-proxy --- nginx-proxy/README.md | 154 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 nginx-proxy/README.md diff --git a/nginx-proxy/README.md b/nginx-proxy/README.md new file mode 100644 index 0000000..d207f45 --- /dev/null +++ b/nginx-proxy/README.md @@ -0,0 +1,154 @@ +# Nginx Proxy + +A custom nginx-proxy image based on [jwilder/nginx-proxy](https://github.com/nginx-proxy/nginx-proxy) with additional features for WordPress and EasyEngine environments. + +## Features + +- Automatic reverse proxy configuration via Docker container labels +- SSL/TLS support with automatic certificate detection +- HTTP Basic Authentication support +- Wildcard HTTP Auth for WordPress Multisite +- Custom vhost configurations +- Access Control Lists (ACL) + +--- + +## HTTP Basic Authentication + +### Standard Authentication + +Create htpasswd files in `/etc/nginx/htpasswd/` to enable HTTP auth: + +```bash +# For a specific domain +htpasswd -c /etc/nginx/htpasswd/example.com username + +# Default auth for all sites without specific htpasswd +htpasswd -c /etc/nginx/htpasswd/default username +``` + +### Wildcard Authentication (WordPress Multisite) + +For WordPress multisite with subdomain configuration, you can use a single htpasswd file to protect both the main domain and all subdomains. + +#### Naming Convention + +Use the `_wildcard.` prefix: + +``` +/etc/nginx/htpasswd/_wildcard.domain.com +``` + +This file will apply HTTP auth to: +- `domain.com` (main domain) +- `*.domain.com` (all subdomains like `blog.domain.com`, `shop.domain.com`, etc.) + +#### Lookup Order + +The template checks for htpasswd files in this order: + +1. **Exact match**: `/etc/nginx/htpasswd/blog.domain.com` +2. **Wildcard match**: `/etc/nginx/htpasswd/_wildcard.domain.com` +3. **Default**: `/etc/nginx/htpasswd/default` + +#### Example Setup + +```bash +# Create wildcard htpasswd for WordPress multisite +htpasswd -c /etc/nginx/htpasswd/_wildcard.example.com admin + +# Optional: Override for a specific subdomain +htpasswd -c /etc/nginx/htpasswd/api.example.com api_user +``` + +#### Multi-level TLDs + +For domains with multi-level TLDs (e.g., `domain.co.uk`, `domain.com.au`), the wildcard logic extracts the last 2 parts only. Create specific htpasswd files for these cases: + +```bash +# For domain.co.uk multisite +htpasswd -c /etc/nginx/htpasswd/domain.co.uk username +htpasswd -c /etc/nginx/htpasswd/blog.domain.co.uk username +# etc. +``` + +--- + +## Access Control Lists (ACL) + +Create ACL files to restrict access by IP: + +```bash +# Per-domain ACL +/etc/nginx/vhost.d/example.com_acl + +# Default ACL for all sites +/etc/nginx/vhost.d/default_acl +``` + +Example ACL content: +```nginx +allow 192.168.1.0/24; +allow 10.0.0.0/8; +deny all; +``` + +--- + +## Custom Vhost Configuration + +### Per-domain configuration + +```bash +# Main vhost config +/etc/nginx/vhost.d/example.com + +# Location-specific config +/etc/nginx/vhost.d/example.com_location +``` + +### Default configuration + +```bash +/etc/nginx/vhost.d/default +/etc/nginx/vhost.d/default_location +``` + +--- + +## Environment Variables + +| Variable | Description | Default | +|----------|-------------|---------| +| `VIRTUAL_HOST` | Comma-separated list of domains | - | +| `VIRTUAL_PORT` | Port to proxy to | `80` | +| `VIRTUAL_PROTO` | Protocol (`http`, `https`, `uwsgi`, `fastcgi`) | `http` | +| `HTTPS_METHOD` | `redirect`, `noredirect`, `nohttps` | `redirect` | +| `SSL_POLICY` | SSL/TLS policy | `Mozilla-Modern` | +| `HSTS` | HSTS header value | `max-age=31536000` | +| `CERT_NAME` | Custom certificate name | auto-detected | +| `NETWORK_ACCESS` | `external` or `internal` | `external` | + +--- + +## Docker Compose Example + +```yaml +services: + nginx-proxy: + image: your-nginx-proxy-image + ports: + - "80:80" + - "443:443" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs:ro + - ./htpasswd:/etc/nginx/htpasswd:ro + - ./vhost.d:/etc/nginx/vhost.d:ro + + wordpress-multisite: + image: wordpress + environment: + - VIRTUAL_HOST=example.com,*.example.com + # HTTP auth via /etc/nginx/htpasswd/_wildcard.example.com +``` From ae1a06bb134cd94f9df3dd3f3685498da4098dec Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 6 Jan 2026 23:46:36 +0530 Subject: [PATCH 3/6] feat(nginx): enhance wildcard htpasswd support for TLDs --- nginx-proxy/nginx.tmpl | 49 +++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/nginx-proxy/nginx.tmpl b/nginx-proxy/nginx.tmpl index 4b0134d..ee55764 100644 --- a/nginx-proxy/nginx.tmpl +++ b/nginx-proxy/nginx.tmpl @@ -64,33 +64,42 @@ {{/* Wildcard htpasswd support for WordPress Multisite. Naming convention: _wildcard.domain.com applies to domain.com AND *.domain.com - Note: For multi-level TLDs (e.g., domain.co.uk), create specific htpasswd files. + Supports multi-level TLDs: _wildcard.domain.co.uk works for domain.co.uk AND *.domain.co.uk + Lookup order: last 3 parts first, then last 2 parts (for multi-level TLD support) */}} {{ else }} {{ $hostParts := split .Host "." }} {{ $partsLen := len $hostParts }} - {{ if ge $partsLen 2 }} - {{/* Build base domain from last 2 parts: e.g., blog.domain.com -> domain.com */}} - {{ $lastIndex := sub $partsLen 1 }} - {{ $secondLastIndex := sub $partsLen 2 }} - {{ $baseDomain := printf "%s.%s" (index $hostParts $secondLastIndex) (index $hostParts $lastIndex) }} - {{ $wildcardHtpasswd := printf "/etc/nginx/htpasswd/_wildcard.%s" $baseDomain }} - {{ if (exists $wildcardHtpasswd) }} - auth_basic "Restricted {{ .Host }}"; - auth_basic_user_file {{ $wildcardHtpasswd }}; - {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} - include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; - {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} - include /etc/nginx/vhost.d/default_acl; - {{ end }} - {{ else if (exists "/etc/nginx/htpasswd/default") }} + {{ $foundWildcard := "" }} + {{/* Check last 3 parts first (e.g., domain.co.uk for blog.domain.co.uk) */}} + {{ if ge $partsLen 3 }} + {{ $idx3 := sub $partsLen 3 }} + {{ $idx2 := sub $partsLen 2 }} + {{ $idx1 := sub $partsLen 1 }} + {{ $baseDomain3 := printf "%s.%s.%s" (index $hostParts $idx3) (index $hostParts $idx2) (index $hostParts $idx1) }} + {{ $wildcardHtpasswd3 := printf "/etc/nginx/htpasswd/_wildcard.%s" $baseDomain3 }} + {{ if (exists $wildcardHtpasswd3) }} + {{ $foundWildcard = $wildcardHtpasswd3 }} + {{ end }} + {{ end }} + {{/* If not found, check last 2 parts (e.g., domain.com for blog.domain.com) */}} + {{ if and (eq $foundWildcard "") (ge $partsLen 2) }} + {{ $idx2 := sub $partsLen 2 }} + {{ $idx1 := sub $partsLen 1 }} + {{ $baseDomain2 := printf "%s.%s" (index $hostParts $idx2) (index $hostParts $idx1) }} + {{ $wildcardHtpasswd2 := printf "/etc/nginx/htpasswd/_wildcard.%s" $baseDomain2 }} + {{ if (exists $wildcardHtpasswd2) }} + {{ $foundWildcard = $wildcardHtpasswd2 }} + {{ end }} + {{ end }} + {{/* Apply the found wildcard or fall back to default */}} + {{ if ne $foundWildcard "" }} auth_basic "Restricted {{ .Host }}"; - auth_basic_user_file /etc/nginx/htpasswd/default; - {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} + auth_basic_user_file {{ $foundWildcard }}; + {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; - {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} + {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} include /etc/nginx/vhost.d/default_acl; - {{ end }} {{ end }} {{ else if (exists "/etc/nginx/htpasswd/default") }} auth_basic "Restricted {{ .Host }}"; From 5542caf7f068dcfdae162aab694f369e7a7c392d Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Tue, 6 Jan 2026 23:46:40 +0530 Subject: [PATCH 4/6] docs(readme): update wildcard auth section for multi-level TLDs --- nginx-proxy/README.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/nginx-proxy/README.md b/nginx-proxy/README.md index d207f45..4e33b8f 100644 --- a/nginx-proxy/README.md +++ b/nginx-proxy/README.md @@ -48,8 +48,9 @@ This file will apply HTTP auth to: The template checks for htpasswd files in this order: 1. **Exact match**: `/etc/nginx/htpasswd/blog.domain.com` -2. **Wildcard match**: `/etc/nginx/htpasswd/_wildcard.domain.com` -3. **Default**: `/etc/nginx/htpasswd/default` +2. **Wildcard (3 parts)**: `/etc/nginx/htpasswd/_wildcard.domain.com` (for multi-level TLD support) +3. **Wildcard (2 parts)**: `/etc/nginx/htpasswd/_wildcard.com` (fallback) +4. **Default**: `/etc/nginx/htpasswd/default` #### Example Setup @@ -63,13 +64,20 @@ htpasswd -c /etc/nginx/htpasswd/api.example.com api_user #### Multi-level TLDs -For domains with multi-level TLDs (e.g., `domain.co.uk`, `domain.com.au`), the wildcard logic extracts the last 2 parts only. Create specific htpasswd files for these cases: +Multi-level TLDs (e.g., `.co.in`, `.com.au`) are fully supported. The template checks progressively: + +1. **Last 3 parts first**: `_wildcard.domain.co.in` for `blog.domain.co.in` +2. **Then last 2 parts**: `_wildcard.co.in` as fallback ```bash -# For domain.co.uk multisite -htpasswd -c /etc/nginx/htpasswd/domain.co.uk username -htpasswd -c /etc/nginx/htpasswd/blog.domain.co.uk username -# etc. +# For domain.co.in multisite +htpasswd -c /etc/nginx/htpasswd/_wildcard.domain.co.in admin + +# This will protect: +# - domain.co.in +# - blog.domain.co.in +# - shop.domain.co.in +# - etc. ``` --- From a21ca478bf096813f6941c60eec0c30d51b793d7 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Thu, 8 Jan 2026 10:01:50 +0530 Subject: [PATCH 5/6] feat(nginx): enhance wildcard htpasswd support for multi-level TLDs --- nginx-proxy/nginx.tmpl | 89 ++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 33 deletions(-) diff --git a/nginx-proxy/nginx.tmpl b/nginx-proxy/nginx.tmpl index ee55764..a431cf6 100644 --- a/nginx-proxy/nginx.tmpl +++ b/nginx-proxy/nginx.tmpl @@ -61,17 +61,22 @@ {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} include /etc/nginx/vhost.d/default_acl; {{ end }} - {{/* + {{/* Wildcard htpasswd support for WordPress Multisite. Naming convention: _wildcard.domain.com applies to domain.com AND *.domain.com - Supports multi-level TLDs: _wildcard.domain.co.uk works for domain.co.uk AND *.domain.co.uk - Lookup order: last 3 parts first, then last 2 parts (for multi-level TLD support) + Supports multi-level TLDs: _wildcard.domain.co.in works for domain.co.in AND *.domain.co.in + + Lookup order (after exact match check on line 56): + - For 3+ part domains: checks _wildcard.{last-3-parts}, then falls back to default + - For 2-part domains: checks _wildcard.{domain}, then falls back to default + - For single-part hostnames: uses default only + + Note: Uses sprig's splitList and sub functions (available in docker-gen 0.7.4+) */}} {{ else }} - {{ $hostParts := split .Host "." }} + {{ $hostParts := splitList "." .Host }} {{ $partsLen := len $hostParts }} - {{ $foundWildcard := "" }} - {{/* Check last 3 parts first (e.g., domain.co.uk for blog.domain.co.uk) */}} + {{/* Check last 3 parts first (e.g., domain.co.in for blog.domain.co.in) */}} {{ if ge $partsLen 3 }} {{ $idx3 := sub $partsLen 3 }} {{ $idx2 := sub $partsLen 2 }} @@ -79,35 +84,53 @@ {{ $baseDomain3 := printf "%s.%s.%s" (index $hostParts $idx3) (index $hostParts $idx2) (index $hostParts $idx1) }} {{ $wildcardHtpasswd3 := printf "/etc/nginx/htpasswd/_wildcard.%s" $baseDomain3 }} {{ if (exists $wildcardHtpasswd3) }} - {{ $foundWildcard = $wildcardHtpasswd3 }} + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file {{ ($wildcardHtpasswd3) }}; + {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} + include /etc/nginx/vhost.d/default_acl; + {{ end }} + {{ else if (exists "/etc/nginx/htpasswd/default") }} + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file /etc/nginx/htpasswd/default; + {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} + include /etc/nginx/vhost.d/default_acl; + {{ end }} {{ end }} - {{ end }} - {{/* If not found, check last 2 parts (e.g., domain.com for blog.domain.com) */}} - {{ if and (eq $foundWildcard "") (ge $partsLen 2) }} + {{ else if ge $partsLen 2 }} + {{/* Only 2 parts (e.g., domain.com) - check wildcard directly */}} {{ $idx2 := sub $partsLen 2 }} {{ $idx1 := sub $partsLen 1 }} {{ $baseDomain2 := printf "%s.%s" (index $hostParts $idx2) (index $hostParts $idx1) }} {{ $wildcardHtpasswd2 := printf "/etc/nginx/htpasswd/_wildcard.%s" $baseDomain2 }} {{ if (exists $wildcardHtpasswd2) }} - {{ $foundWildcard = $wildcardHtpasswd2 }} - {{ end }} - {{ end }} - {{/* Apply the found wildcard or fall back to default */}} - {{ if ne $foundWildcard "" }} - auth_basic "Restricted {{ .Host }}"; - auth_basic_user_file {{ $foundWildcard }}; - {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} - include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; - {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} - include /etc/nginx/vhost.d/default_acl; + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file {{ ($wildcardHtpasswd2) }}; + {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} + include /etc/nginx/vhost.d/default_acl; + {{ end }} + {{ else if (exists "/etc/nginx/htpasswd/default") }} + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file /etc/nginx/htpasswd/default; + {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} + include /etc/nginx/vhost.d/default_acl; + {{ end }} {{ end }} {{ else if (exists "/etc/nginx/htpasswd/default") }} - auth_basic "Restricted {{ .Host }}"; - auth_basic_user_file /etc/nginx/htpasswd/default; + {{/* Single-part hostname - use default */}} + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file /etc/nginx/htpasswd/default; {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} - include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; + include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} - include /etc/nginx/vhost.d/default_acl; + include /etc/nginx/vhost.d/default_acl; {{ end }} {{ end }} {{ end }} @@ -187,8 +210,8 @@ map $scheme $proxy_x_forwarded_ssl { gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; log_format vhost '$host $remote_addr - $remote_user [$time_local] ' - '"$request" $status $body_bytes_sent ' - '"$http_referer" "$http_user_agent"'; + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent"'; {{ if $.Env.RESOLVERS }} resolver {{ $.Env.RESOLVERS }}; @@ -231,14 +254,14 @@ server { {{ end }} root /etc/nginx/html; - + # Custom error page for 503 error_page 503 /default.html; - + location / { return 503; } - + # Serve the error page without redirect location = /default.html { root /etc/nginx/html; @@ -260,14 +283,14 @@ server { {{ end }} root /etc/nginx/html; - + # Custom error page for 503 error_page 503 /default.html; - + location / { return 503; } - + # Serve the error page without redirect location = /default.html { root /etc/nginx/html; From fe131a0007fa5913027099684cdda6aaca846697 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Thu, 8 Jan 2026 10:38:22 +0530 Subject: [PATCH 6/6] fix(nginx-proxy): Correct wildcard htpasswd lookup for 3-part domains Fix bug where blog.example.com incorrectly checked for _wildcard.blog.example.com instead of _wildcard.example.com. Changes: - 4+ part domains: check 3-part wildcard first, then 2-part fallback - 2-3 part domains: check 2-part wildcard directly - Fixed template formatting to match original style - Updated README with corrected lookup table --- nginx-proxy/README.md | 18 ++++++++++++------ nginx-proxy/nginx.tmpl | 37 +++++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/nginx-proxy/README.md b/nginx-proxy/README.md index 4e33b8f..c07ef4e 100644 --- a/nginx-proxy/README.md +++ b/nginx-proxy/README.md @@ -48,8 +48,8 @@ This file will apply HTTP auth to: The template checks for htpasswd files in this order: 1. **Exact match**: `/etc/nginx/htpasswd/blog.domain.com` -2. **Wildcard (3 parts)**: `/etc/nginx/htpasswd/_wildcard.domain.com` (for multi-level TLD support) -3. **Wildcard (2 parts)**: `/etc/nginx/htpasswd/_wildcard.com` (fallback) +2. **Wildcard (3 parts)**: `/etc/nginx/htpasswd/_wildcard.domain.co.in` (for 4+ part domains only) +3. **Wildcard (2 parts)**: `/etc/nginx/htpasswd/_wildcard.example.com` (for 2-3 part domains, or fallback) 4. **Default**: `/etc/nginx/htpasswd/default` #### Example Setup @@ -58,19 +58,25 @@ The template checks for htpasswd files in this order: # Create wildcard htpasswd for WordPress multisite htpasswd -c /etc/nginx/htpasswd/_wildcard.example.com admin +# This protects: example.com, blog.example.com, shop.example.com, etc. + # Optional: Override for a specific subdomain htpasswd -c /etc/nginx/htpasswd/api.example.com api_user ``` #### Multi-level TLDs -Multi-level TLDs (e.g., `.co.in`, `.com.au`) are fully supported. The template checks progressively: +Multi-level TLDs (e.g., `.co.in`, `.com.au`) are fully supported: -1. **Last 3 parts first**: `_wildcard.domain.co.in` for `blog.domain.co.in` -2. **Then last 2 parts**: `_wildcard.co.in` as fallback +| Host | Wildcard File Checked | +|------|----------------------| +| `blog.domain.co.in` (4 parts) | `_wildcard.domain.co.in` first, then `_wildcard.co.in` | +| `domain.co.in` (3 parts) | `_wildcard.co.in` | +| `blog.example.com` (3 parts) | `_wildcard.example.com` | +| `example.com` (2 parts) | `_wildcard.example.com` | ```bash -# For domain.co.in multisite +# For domain.co.in multisite (multi-level TLD) htpasswd -c /etc/nginx/htpasswd/_wildcard.domain.co.in admin # This will protect: diff --git a/nginx-proxy/nginx.tmpl b/nginx-proxy/nginx.tmpl index a431cf6..e12ba51 100644 --- a/nginx-proxy/nginx.tmpl +++ b/nginx-proxy/nginx.tmpl @@ -67,8 +67,8 @@ Supports multi-level TLDs: _wildcard.domain.co.in works for domain.co.in AND *.domain.co.in Lookup order (after exact match check on line 56): - - For 3+ part domains: checks _wildcard.{last-3-parts}, then falls back to default - - For 2-part domains: checks _wildcard.{domain}, then falls back to default + - For 4+ part domains: checks _wildcard.{last-3-parts}, then _wildcard.{last-2-parts}, then default + - For 2-3 part domains: checks _wildcard.{last-2-parts}, then falls back to default - For single-part hostnames: uses default only Note: Uses sprig's splitList and sub functions (available in docker-gen 0.7.4+) @@ -76,8 +76,8 @@ {{ else }} {{ $hostParts := splitList "." .Host }} {{ $partsLen := len $hostParts }} - {{/* Check last 3 parts first (e.g., domain.co.in for blog.domain.co.in) */}} - {{ if ge $partsLen 3 }} + {{/* For 4+ part domains, check last 3 parts first (e.g., _wildcard.domain.co.in for blog.domain.co.in) */}} + {{ if ge $partsLen 4 }} {{ $idx3 := sub $partsLen 3 }} {{ $idx2 := sub $partsLen 2 }} {{ $idx1 := sub $partsLen 1 }} @@ -91,17 +91,30 @@ {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} include /etc/nginx/vhost.d/default_acl; {{ end }} - {{ else if (exists "/etc/nginx/htpasswd/default") }} - auth_basic "Restricted {{ .Host }}"; - auth_basic_user_file /etc/nginx/htpasswd/default; - {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} - include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; - {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} - include /etc/nginx/vhost.d/default_acl; + {{ else }} + {{/* Fallback: check last 2 parts (e.g., _wildcard.co.in for blog.domain.co.in) */}} + {{ $baseDomain2 := printf "%s.%s" (index $hostParts $idx2) (index $hostParts $idx1) }} + {{ $wildcardHtpasswd2 := printf "/etc/nginx/htpasswd/_wildcard.%s" $baseDomain2 }} + {{ if (exists $wildcardHtpasswd2) }} + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file {{ ($wildcardHtpasswd2) }}; + {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} + include /etc/nginx/vhost.d/default_acl; + {{ end }} + {{ else if (exists "/etc/nginx/htpasswd/default") }} + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file /etc/nginx/htpasswd/default; + {{ if (exists (printf "/etc/nginx/vhost.d/%s_acl" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_acl" .Host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_acl") }} + include /etc/nginx/vhost.d/default_acl; + {{ end }} {{ end }} {{ end }} {{ else if ge $partsLen 2 }} - {{/* Only 2 parts (e.g., domain.com) - check wildcard directly */}} + {{/* For 2-3 part domains, check last 2 parts (e.g., _wildcard.example.com for blog.example.com or example.com) */}} {{ $idx2 := sub $partsLen 2 }} {{ $idx1 := sub $partsLen 1 }} {{ $baseDomain2 := printf "%s.%s" (index $hostParts $idx2) (index $hostParts $idx1) }}