Repository: certbot/certbot

Issue:
certbot adds acme-challenge to wrong config, if domain name is not lower case
- Debian 9.6
- I installed Certbot with OS package manager
- certbot 0.28.0
- nginx

- had this host in my config in `/etc/nginx/conf.d/RussianChurchVancouver.ca.conf`:  
```
server {
  listen       80;
  server_name  RussianChurchVancouver.ca www.RussianChurchVancouver.ca;
...
```

- I ran certbot and certs were not created, because certbot failed:
```
root@deb96:/var/www/RussianChurchVancouver.ca/web# certbot -m slavikca@gmail.com --agree-tos --nginx -d RussianChurchVancouver.ca -d www.RussianChurchVancouver.ca
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for russianchurchvancouver.ca
http-01 challenge for www.russianchurchvancouver.ca
nginx: [warn] conflicting server name "www.russianchurchvancouver.ca" on 0.0.0.0:80, ignored
nginx: [warn] conflicting server name "russianchurchvancouver.ca" on 0.0.0.0:80, ignored
Waiting for verification...
Cleaning up challenges
Failed authorization procedure. russianchurchvancouver.ca (http-01): urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://russianchurchvancouver.ca/.well-known/acme-challenge/b4vlj_zIdB4H_a94FlltJWx2JBGBDS_ihAFWrpJSl5U: "<html>\r\n<head><title>404 Not Found</title></head>\r\n<body>\r\n<center><h1>404 Not Found</h1></center>\r\n<hr><center>nginx</center>\r\n", www.russianchurchvancouver.ca (http-01): urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://www.russianchurchvancouver.ca/.well-known/acme-challenge/B8e0i1p0jhjNtfV1Dd36rlE8eh4K2bpefVvABc6Na48: "<html>\r\n<head><title>404 Not Found</title></head>\r\n<body>\r\n<center><h1>404 Not Found</h1></center>\r\n<hr><center>nginx</center>\r\n"
```

While troubleshooting, I found, that  certbot adding acme-challenge to this config file:
```
Writing nginx conf tree to /etc/nginx/conf.d/default.conf
```
which is the bug. that's why I have `conflicting server name` in the log (certbot created situation when I have `russianchurchvancouver.ca` both in `default.conf` and in `RussianChurchVancouver.ca.conf`
Expected, that it would add acme-challenge to this file:
```
/etc/nginx/conf.d/RussianChurchVancouver.ca.conf
```

At this point, I started to suspect, that certbot does that because my domains in config file are not lower case.
So, I lowercased them:
```
  server_name  russianchurchvancouver.ca www.russianchurchvancouver.ca;
```
and certbot worked correctly:
```
root@deb96:/etc/nginx/conf.d# certbot -m slavikca@gmail.com --agree-tos --nginx -d russianchurchvancouver.ca,www.russianchurchvancouver.ca
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for www.russianchurchvancouver.ca
http-01 challenge for russianchurchvancouver.ca
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/conf.d/RussianChurchVancouver.ca.conf
Deploying Certificate to VirtualHost /etc/nginx/conf.d/RussianChurchVancouver.ca.conf
...
Congratulations! You have successfully enabled https://russianchurchvancouver.ca
and https://www.russianchurchvancouver.ca
```


Discussion:
Thanks for reporting, this sure is a bug! You're right, the fix for now is to make sure to match the case to what's written in the config files.
We've made a lot of changes to Certbot since this issue was opened. If you still have this issue with an up-to-date version of Certbot, can you please add a comment letting us know? This helps us to better see what issues are still affecting our users. If there is no activity in the next 30 days, this issue will be automatically closed.

This is still a bug.

Resolving patch:
diff --git a/certbot-nginx/certbot_nginx/_internal/parser.py b/certbot-nginx/certbot_nginx/_internal/parser.py
--- a/certbot-nginx/certbot_nginx/_internal/parser.py
+++ b/certbot-nginx/certbot_nginx/_internal/parser.py
@@ -496,7 +496,8 @@ def get_best_match(target_name, names):
 
 
 def _exact_match(target_name, name):
-    return name in (target_name, '.' + target_name)
+    target_lower = target_name.lower()
+    return name.lower() in (target_lower, '.' + target_lower)
 
 
 def _wildcard_match(target_name, name, start):
@@ -517,11 +518,11 @@ def _wildcard_match(target_name, name, start):
     if first not in ('*', ''):
         return False
 
-    target_name = '.'.join(parts)
-    name = '.'.join(match_parts)
+    target_name_lower = '.'.join(parts).lower()
+    name_lower = '.'.join(match_parts).lower()
 
     # Ex: www.eff.org matches *.eff.org, eff.org does not match *.eff.org
-    return target_name.endswith('.' + name)
+    return target_name_lower.endswith('.' + name_lower)
 
 
 def _regex_match(target_name, name):


Test patch:
diff --git a/certbot-nginx/tests/parser_test.py b/certbot-nginx/tests/parser_test.py
--- a/certbot-nginx/tests/parser_test.py
+++ b/certbot-nginx/tests/parser_test.py
@@ -340,7 +340,9 @@ def test_get_best_match(self):
                  {'*.www.eff.org', 'www.*'},
                  {'*.org'},
                  set(),
-                 {'example.com'}]
+                 {'example.com'},
+                 {'www.Eff.org'},
+                 {'.efF.org'}]
         winners = [('exact', 'www.eff.org'),
                    (None, None),
                    ('exact', '.www.eff.org'),
@@ -353,7 +355,9 @@ def test_get_best_match(self):
                    ('wildcard_end', 'www.*'),
                    ('wildcard_start', '*.org'),
                    (None, None),
-                   (None, None)]
+                   (None, None),
+                   ('exact', 'www.Eff.org'),
+                   ('wildcard_start', '.efF.org')]
 
         for i, winner in enumerate(winners):
             self.assertEqual(winner,