Obtaining a cert for a domain that's protected by http auth

Hi there,

I’m trying to figure out what the best solution is for obtaining a cert for a domain that is protected by http authentication without temporarily taking the site offline.

does the certbot authentication tool allow for a command to include the http auth user:pass to get past the protection to obtain a cert? if not, does certbot/let’s encrypt have a list of IPs I can add to my config to allow it to get past the http auth restriction?

thanks!

Can’t you open up /.well-known/acme-challenge/ for all users?

Also, the tls-sni-01 challenge uses its own virtualhost, so wouldn’t be affected by settings in some other virtualhost.

1 Like

Although obviously it must be true that Let’s Encrypt is checking from particular IP addresses they don’t publish those and they are subject to change at any time. You should avoid having special behaviour just for some IP addresses.

You have essentially three options, one of which is not (yet, today) possible with certbot but can use alternative clients

  1. You could whitelist just the path certbot cares about, which is /.well-known/acme-challenge/ so that no authentication is required for this path. Ordinary users would still need to do HTTP auth, but the ACME server, Let’s Encrypt, which is only interested in paths in that directory, would not.

  2. You could use the TLS-SNI validation. Certbot knows how to do this when it acts as your web server, but that probably doesn’t help you if you want to run an actual web server with the certificate at the end. I believe Certbot knows how to configure Apache to pass this challenge, so it’s an option if you use Apache. Otherwise it’s probably too tricky to arrange.

  3. You could use DNS validation. This is the one that certbot can’t help with, but other clients can if you’re able to change your DNS records automatically (e.g. via an API).

2 Likes

thanks for the replies. I’ve been trying to get auth_basic for nginx to allow access to a directory without a password, but so far I haven’t been able to get it to work correctly - it keeps prompting for a password when I try to manually browse to the mysite.com/.well-known/acme-challenge directory…

if anyone is good with nginx and can lend a hand, that’d be fantastic! here’s my conf (slightly altered to obscure some stuff):

server {
        listen 80;
        listen [::]:80;

        root /usr/share/mysite;
        index index.php index.html index.htm;

        # Make site accessible from http://localhost/
        server_name mysite.com www.mysite.com;

        # Logs
        access_log /usr/share/logs/access.log;
        error_log /usr/share/logs/error.log info;

        location / {
                try_files $uri $uri/ =404;
                auth_basic "Admin Login";
                auth_basic_user_file /etc/nginx/auth;
        }

        location /.well-known/ {
                auth_basic "off";
        }

        error_page 404 /404.html;
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
                root /usr/share/nginx/html;
        }

        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;
        }
}

…I’ve tried both /.well-known/ and /.well-known/acme-challenge/ for the 2nd location block as well as with and without quotes around off in auth_basic.

Try with

location /.well-known/ {
        auth_basic off;
}

without the quote

I tried that.

my issue was resolved by adding autoindex on; to the location block, like so:

location /.well-known {
autoindex on;
auth_basic "off";
}

once I did that, restarted nginx and tested it, it worked. then I went back and did a dry run on obtaining certs and was presented with this:

IMPORTANT NOTES:

  • The dry run was successful.

:smiley:

2 Likes

now that I got my initial issue worked out and cleanly obtained my certs, do I need to force nginx to reload after running the letsencrypt-auto renew command or will the renewal script tried to reload the nginx?

Assuming you haven’t got either the experimental nginx plugin setup, or your own custom plugin, Let’s Encrypt doesn’t know about nginx, so it won’t cause a reload.

The command line option --post-hook can be used to run a command only when one or more renewals actually happened, so you could tell this to perform an nginx reload, which will cause nginx to notice the renewed certificate and use it.

Because certbot is smart enough to not renew certificates until they have 30 days or less left to expire, you can set up a job to run every morning, most mornings it will do nothing, and then with the hook setting on the occasions it does renew it will automatically ask nginx to reload.

Note that reload (unlike “restart” or manually stopping and starting) doesn’t interrupt service, the web server may be a tiny bit slower to respond for a few seconds, but no visitors get dropped.

1 Like

If you’re interested in seeing what tialaramex is talking about “in the wild”, you can take a look at the script I have running to renew my certificates. In my case the --post-hook command gets a bit lengthy because I actually have to accomplish several things:

  1. Reload nginx to pick up the new certificates
  2. Copy the relevant certificate into a path that my Jabber server can access
  3. Restart aforementioned Jabber server to pick up the new certificate

Note: tialaramex’s original post mentioned the --renew-hook option, whereas I’m using --post-hook. The two are basically the same, save that --renew-hook is used for each certificate as it is renewed, whereas --post-hook is only called once after all certificates have been renewed (though in either case only if there’s actually been a renewal issued).

I have this script cron’d up on my server to run weekly. Disclaimer: It’s still new enough that it hasn’t actually issued any renewals yet, so while I’m confident it will work when the time comes that’s hardly a proven assessment. (I think the renewal will happen when the certificate has <30 days left of validity, so I’m expecting the first batch of renewed certificates on Sunday since they expire on the 31st…)

1 Like

Your choice of hook for this problem makes more sense, I will fix my post above to recommend --post-hook

can I just add --post-hook to the end of my command in a crontab?

example:

30 2 * * 1 /opt/letsencrypt/letsencrypt-auto renew --post-hook  >> /var/log/le-renew.log

I modified my above crontab command and it went through the --dry-run without issues:

sudo ./certbot-auto renew --post-hook "service nginx reload" --dry-run

Processing /etc/letsencrypt/renewal/mysite.com.conf
-------------------------------------------------------------------------------
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/mysite.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)

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