A Certbot webroot challenge lets an existing HTTP site answer ACME validation without stopping the web server or letting Certbot edit the virtual host. It works only when the domain, public port 80, document root, and challenge path all point at the same content.
The webroot authenticator writes a temporary token file below the selected document root. The running web server must then serve that file from the public challenge path for the domain so the certificate authority can retrieve it over HTTP-01 validation.
The example flow uses one document root for both the apex and www hostnames. Replace the names, webroot path, and account email with the real site values, and use a DNS challenge instead when port 80 is blocked, the site is private-only, or a wildcard certificate is required.
Steps to use a Certbot webroot challenge:
- Confirm that the domain resolves to the server that serves the HTTP site.
$ getent ahosts site.example.net 203.0.113.10 STREAM site.example.net 203.0.113.10 DGRAM 203.0.113.10 RAW
Check every name that will appear on the certificate. If a name has an .AAAA record, that IPv6 address must serve the same challenge path or HTTP-01 validation can fail from validators that choose IPv6.
- Confirm the web server's document root for the site.
$ sudo nginx -T nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful # configuration file /etc/nginx/sites-enabled/site.example.net: server { listen 80; server_name site.example.net www.site.example.net; root /var/www/site.example.net; } ##### snipped #####Use the directory that the active virtual host serves for the requested name. On Apache, this is usually the matching DocumentRoot value instead of the Nginx root directive.
- Create the challenge directory inside the webroot.
$ sudo mkdir -p /var/www/site.example.net/.well-known/acme-challenge
Certbot can create its own challenge files, but creating the directory first makes hidden-directory and permission problems visible before the ACME request.
- Write a short probe file into the challenge directory.
$ printf 'challenge-ok\n' | sudo tee /var/www/site.example.net/.well-known/acme-challenge/probe-token challenge-ok
- Confirm that the probe file is reachable over public HTTP.
$ curl http://site.example.net/.well-known/acme-challenge/probe-token challenge-ok
HTTP-01 starts on port 80. Redirects can work when they preserve the challenge URL and stay on ports 80 or 443, but a redirect to a login page, a different host, or a blocked hidden directory will fail validation.
- Confirm that Certbot has the webroot authenticator.
$ certbot plugins Saving debug log to /var/log/letsencrypt/letsencrypt.log ##### snipped ##### * webroot Description: Saves the necessary validation files to a .well-known/acme-challenge/ directory within the nominated webroot path. A separate HTTP server must be running and serving files from the webroot path. HTTP challenge only (wildcards not supported). Interfaces: Authenticator, Plugin ##### snipped #####
- Rehearse the certificate request with the staging service.
$ sudo certbot certonly --webroot -w /var/www/site.example.net -d site.example.net -d www.site.example.net -m admin@example.net --agree-tos --dry-run Saving debug log to /var/log/letsencrypt/letsencrypt.log Simulating a certificate request for site.example.net and www.site.example.net The dry run was successful.
For domains served from different document roots, place the matching -w option before the -d names that use that webroot.
–dry-run uses the staging service and does not save a production certificate.
- Request the production certificate after the dry run succeeds.
$ sudo certbot certonly --webroot -w /var/www/site.example.net -d site.example.net -d www.site.example.net -m admin@example.net --agree-tos Saving debug log to /var/log/letsencrypt/letsencrypt.log Requesting a certificate for site.example.net and www.site.example.net Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/site.example.net/fullchain.pem Key is saved at: /etc/letsencrypt/live/site.example.net/privkey.pem
This command obtains the certificate only. Install /etc/letsencrypt/live/site.example.net/fullchain.pem and /etc/letsencrypt/live/site.example.net/privkey.pem in the web server configuration before expecting HTTPS traffic to use the new certificate.
- Confirm that Certbot recorded the certificate with the expected names.
$ sudo certbot certificates --cert-name site.example.net Saving debug log to /var/log/letsencrypt/letsencrypt.log Found the following certs: Certificate Name: site.example.net Domains: site.example.net www.site.example.net Expiry Date: 2026-09-09 12:34:56+00:00 (VALID: 89 days) Certificate Path: /etc/letsencrypt/live/site.example.net/fullchain.pem Private Key Path: /etc/letsencrypt/live/site.example.net/privkey.pem - Test renewal with the saved webroot configuration.
$ sudo certbot renew --cert-name site.example.net --dry-run Saving debug log to /var/log/letsencrypt/letsencrypt.log Processing /etc/letsencrypt/renewal/site.example.net.conf Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/site.example.net/fullchain.pem (success)
A successful renewal dry run confirms that Certbot can reuse the saved webroot authenticator and challenge path later.
Related: Check the Certbot renewal timer
- Remove the temporary probe file.
$ sudo rm /var/www/site.example.net/.well-known/acme-challenge/probe-token
Certbot removes its own ACME challenge files after validation. Removing the manual probe keeps the challenge directory from serving stale test content.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.