Wildcard cert with Nginx

Please fill out the fields below so we can help you better. Note: you must provide your domain name to get help. Domain names for issued certificates are all made public in Certificate Transparency logs (e.g. https://crt.sh/?q=example.com), so withholding your domain name here does not increase secrecy, but only makes it harder for us to provide help.

My domain is:
https://cmscontracts.com
(and wildcard variants such as https://psiscs.cmscontracts.com)

I ran this command:
sudo certbot --nginx --agree-tos --no-eff-email --no-redirect --keep-until-expiring -m [hidden]@example.com -d cmscontracts.com -d *.cmscontracts.com

It produced this output:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Cert not yet due for renewal
Keeping the existing certificate
Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/chronicle.conf

Which server blocks would you like to modify?


1: File: /etc/nginx/sites-enabled/signyl_for_supply_chain.conf
Addresses: 443 ssl
Names: rails1, signyl_for_supply_chain, signyl.psiapps.com
HTTPS: Yes

2: File: /etc/nginx/sites-enabled/signyl_for_rehab.conf
Addresses: 443 ssl
Names: signyl_for_rehab, rails1, rehab.psiapps.com
HTTPS: Yes

3: File: /etc/nginx/sites-enabled/chronicle.conf
Addresses: 443 ssl
Names: chronicle, cmscontracts.com, *.cmscontracts.com, rails1
HTTPS: Yes


Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter ‘c’ to cancel):

My web server is (include version): nginx version:
nginx/1.16.1

The operating system my web server runs on is (include version):
Linux rails1 4.15.0-1057-aws #59-Ubuntu SMP Wed Dec 4 10:02:00 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

My hosting provider, if applicable, is:
N/A

I can login to a root shell on my machine (yes or no, or I don’t know):
YES

I’m using a control panel to manage my site (no, or provide the name and version of the control panel):
NO

The version of my client is (e.g. output of certbot --version or certbot-auto --version if you’re using Certbot):
certbot 0.31.0

Additional info:
The “server_name” in the Nginx config of the appropriate .conf file is
server_name cmscontracts.com *.cmscontracts.com chronicle rails1;

I’ve tried lots of different domain name combinations. But as long as there’s a * in the server_name, cerbot is unable to identify the server block. It works fine for my other sites that have a non-wildcard domains.

I need to automate the certbot command in a Chef recipe. So I am unable to respond to the prompt.

Thanks for any help.

-Will

1 Like

I’m not quite sure what’s the issue here.
Do you mean that certbot are not able to deploy the certificate everytime you attempt to renew it?

If you are attempting to renew the certificate, you should consider using the renew command, which will simply renew the certificate and reload your Nginx. (File path and chain path will not be changed, so once you had the certificate in virtual host, you are good to go if you setup renewal correct)

1 Like

stevenzhhu thanks for getting back with me. I can understand the confusion. The command I’m using (referenced in the original post) is run every time I deploy. It’s needed because the deploy process overwrites the nginx config files. I need to re-run certbot to update the nginx config files to use the Let’s Encrypt certificates again.

I don’t have a lot of control over the deploy recipes, so I can’t stop them from recreating the nginx config files. The only thing I can do is fix them after the deploy scripts finish by re-running certbot with the --keep-until-expiring option.

The --keep-until-expiring option allows me to update the Nginx config without attempting to renew the certificate every time I deploy. It’s a reasonable compromise and works for all my domains except the wildcard domain. In the case of the wildcard domain, the command I referenced in the original post prompts me to ask which server block to modify. It can’t determine which server block to modify on its own. For the non-wildcard domains (ex: rehab.psiapps.com), certbot is able to determine which server block to modify. But for the wildcard domain (*.cmscontracts,com), certbot gets confused.

Hope this helps clarify the scenario.

1 Like

I’m uncertain what’s happening, but it might be this open issue:

1 Like

you need an authenticator that can perform dns-01 authentication, if you want a wildcard certificate.

if you only want to install it, you should tell certbot so.
certbot install --reinstall --installer nginx --cert-name example.com

1 Like

Thanks for the suggestion. Unfortunately certbot install --reinstall --installer nginx --cert-name cmscontracts.com gives me the same prompt asking which server block to use.

1 Like

Well… which server block needs that certificate?

It’s the second server block with server_name cmscontracts.com *.cmscontracts.com chronicle rails1; in /etc/nginx/sites-enabled/chronicle.conf

I’ve tried every combination of server_name including only *.cmscontracts.com. As long as there’s a wildcard in there, certbot can’t find it.

ubuntu@rails1:~$ cat /etc/nginx/sites-enabled/chronicle.conf
upstream puma_cmscontracts.com {
 server unix:/srv/www/chronicle/shared/sockets/puma.sock fail_timeout=0;
}

server {
  listen 80;
  server_name cmscontracts.com *.cmscontracts.com chronicle rails1;
  access_log /var/log/nginx/cmscontracts.com.access.log;
  error_log /var/log/nginx/cmscontracts.com.error.log info;

  root /srv/www/chronicle/current/public;

  proxy_hide_header X-Powered-By;
  server_tokens off;

  client_max_body_size 30M;
  client_body_timeout 12;
  client_header_timeout 12;
  keepalive_timeout 65;
  send_timeout 10;

  # http support
  location / {
    try_files $uri/index.html $uri/index.htm @puma;
  }

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    add_header Access-Control-Allow-Origin "$http_origin";
    add_header Access-Control-Allow-Methods 'GET, PUT, POST, DELETE';
    add_header Access-Control-Expose-Headers ETag;
    add_header X-Content-Type-Options nosniff;
  }

  location @puma {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_read_timeout 60;
    proxy_send_timeout 60;

    # If you don't find the filename in the static files
    # Then request it from the puma server
    if (!-f $request_filename) {
      proxy_pass http://puma_cmscontracts.com;
      break;
    }
}

  location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
  }



  error_page 500 502 503 504 /500.html;
  location = /500.html {
    root /srv/www/chronicle/current/public;
  }
}

server {
  listen 443;
  server_name cmscontracts.com *.cmscontracts.com chronicle rails1;
  access_log /var/log/nginx/cmscontracts.com-ssl.access.log;
  error_log /var/log/nginx/cmscontracts.com-ssl.error.log info;

  ssl on;
    ssl_certificate /etc/letsencrypt/live/cmscontracts.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/cmscontracts.com/privkey.pem; # managed by Certbot

  ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
  ssl_protocols TLSv1.2;
  ssl_ecdh_curve secp384r1;

  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;
  ssl_stapling on;
  ssl_stapling_verify on;

  root /srv/www/chronicle/current/public;

  proxy_hide_header X-Powered-By;
  server_tokens off;

  client_max_body_size 30M;
  client_body_timeout 12;
  client_header_timeout 12;
  keepalive_timeout 65;
  send_timeout 10;

  location / {
    try_files $uri/index.html $uri/index.htm @puma;
  }

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    add_header Access-Control-Allow-Origin "$http_origin";
    add_header Access-Control-Allow-Methods 'GET, PUT, POST, DELETE';
    add_header Access-Control-Expose-Headers ETag;
    add_header X-Content-Type-Options nosniff;
  }

  location @puma {
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_read_timeout 60;
    proxy_send_timeout 60;

    # If you don't find the filename in the static files
    # Then request it from the puma server
    if (!-f $request_filename) {
      proxy_pass http://puma_cmscontracts.com;
      break;
    }
  }
  error_page 500 502 503 504 /500.html;
  location = /500.html {
    root /srv/www/chronicle/current/public;
  }
}

wait, I see the certificate in this config.

    ssl_certificate /etc/letsencrypt/live/cmscontracts.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/cmscontracts.com/privkey.pem; # managed by Certbot

If you have both names in that same certificate, you’re done.

wait, I see the certificate in this config.

   ssl_certificate /etc/letsencrypt/live/cmscontracts.com/fullchain.pem; # managed by Certbot
   ssl_certificate_key /etc/letsencrypt/live/cmscontracts.com/privkey.pem; # managed by Certbot

If you have both names in that same certificate, you’re done.

Yes, and sorry for the confusion. I ran certbot manually and responded to the prompt myself (referenced in the original post) in order to get here. I did that so I could get the server back online while I work out how to automate it.

I am unable to automate certbot in the deploy because certbot can’t find the server block with a wildcard cert and needs to prompt for it (which won’t work in an automated deploy)

maybe you can script the installer by yourself, without relying on certbot install (or you can go and read the source for the nginx installer plugin and try to understand it)

Since you have a DNS-01 auth to handle the wildcard cert, I think the easiest path would be ignoring the nginx installation part, and using a post-hook (or cronjob) to restart nginx.

Looking at the certbot code, I see that it will always prompt for wildcard domains in Nginx. See:

and

So this is unfortunately the intended behavior and I will need to figure out a different strategy to refresh the Let’s Encrypt cert during deploy.

Thanks everyone for helping me look into this.

A post was merged into an existing topic: Cannot renew certificates

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.