How7o
  • Home
  • Tools
  • Prank Screens
  • Contact
  • Blog
Reading: How to Exclude .well-known from Redirection for Let’s Encrypt in Laravel
Share
Subscribe Now
How7oHow7o
Font ResizerAa
  • Marketing
  • OS
  • Features
  • Guide
  • Complaint
  • Advertise
Search
  • Home
  • Tools
  • Prank Screens
  • Contact
  • Blog
Follow US
Copyright © 2014-2023 Ruby Theme Ltd. All Rights Reserved.
How7o > Blog > Server Management > How to Exclude .well-known from Redirection for Let’s Encrypt in Laravel
Server Management

How to Exclude .well-known from Redirection for Let’s Encrypt in Laravel

how7o
By how7o
Last updated: May 10, 2026
8 Min Read
Laravel .htaccess exclude .well-known for Let's Encrypt ACME challenge
SHARE

Your laravel htaccess well-known rewrite is eating Let’s Encrypt’s ACME challenge — the request for /.well-known/acme-challenge/<token> gets forwarded into public/, Laravel’s router can’t match it, and certbot fails with Invalid response from http://example.com/.well-known/acme-challenge/.... The fix is a single RewriteCond that excludes /.well-known/ from the rewrite. This guide shows the exact rule, where to put it, and the nginx equivalent for non-Apache setups.

Contents
  • TL;DR
  • Why the error happens
  • Fix — one more RewriteCond
  • Verify the fix
  • Nginx equivalent
  • Renewal works automatically
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-04-23 on Apache 2.4 with Laravel 11 on shared cPanel hosting. Originally published 2022-08-05, rewritten and updated 2026-04-23.

TL;DR

In the project-root .htaccess, add a RewriteCond that excludes /.well-known/ before the forwarding rule:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known
    RewriteCond %{REQUEST_URI} !^public
    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

Why the error happens

If you’ve dropped a Laravel app onto shared hosting with the standard “forward everything into public/” .htaccess (see Fix 403 Forbidden on Laravel Shared Hosting), the rule looks like:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^public
    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

When certbot issues a certificate via the HTTP-01 challenge, it does two things:

  1. Writes a token file into /.well-known/acme-challenge/<long-random-string> on your server.
  2. Asks Let’s Encrypt to fetch http://yourdomain.com/.well-known/acme-challenge/<long-random-string> and confirm the token matches.

Apache receives the second request, your .htaccess rewrites it to public/.well-known/acme-challenge/..., Laravel’s router sees an unknown route, and the response is a 404 from Laravel or whatever error page the app is set up to emit. Certbot logs:

Detail: Invalid response from
http://example.com/.well-known/acme-challenge/EXAMPLE_TOKEN

Fix — one more RewriteCond

The existing rule already uses a RewriteCond to prevent an infinite loop on ^public. Add another for /.well-known/:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known
    RewriteCond %{REQUEST_URI} !^public
    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

Both RewriteCond lines must pass before the RewriteRule fires. The first says “URL must not start with /.well-known,” the second says “URL must not already be under public.” If either condition is true (requested path IS /.well-known/... or already starts with public), the rewrite is skipped and Apache serves the file directly from the project root.

The backslash in \.well-known is an escape — regex treats the dot as “any character” without it. Escaping makes sure the rule matches only the literal /.well-known/ path, not something like /1well-known.

laravel htaccess letsencrypt well-known — RewriteCond excludes acme-challenge from the public forwarding rule

Verify the fix

Before re-running certbot, put a test file in place and fetch it over plain HTTP:

mkdir -p .well-known/acme-challenge
echo "hello-acme" > .well-known/acme-challenge/test

curl -sS http://example.com/.well-known/acme-challenge/test
# expected output: hello-acme

If curl returns hello-acme, the rewrite is bypassed correctly. If it returns a Laravel error page or the site’s index, the condition hasn’t taken effect — double-check the file is at the project root (same folder as artisan and composer.json), and that there’s no per-directory .htaccess in .well-known/ overriding things.

Delete the test file once it’s confirmed and run certbot:

rm .well-known/acme-challenge/test
sudo certbot --apache -d example.com -d www.example.com

Nginx equivalent

Nginx doesn’t read .htaccess. The equivalent lives in the server block:

server {
    listen 80;
    server_name example.com;
    root /var/www/example.com/public;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/example.com;
        try_files $uri =404;
    }

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        include fastcgi.conf;
    }
}

The ^~ modifier makes this location block win over any regex location, which matters if you also have a regex block that would otherwise catch the request. root inside the block points at the project root (not public/), so try_files looks for the challenge file in .well-known/acme-challenge/ at the project level.

Renewal works automatically

Once the .well-known exclude is in place, the rule is permanent — the certbot renew cron job uses the same HTTP-01 challenge every ~60 days and succeeds without manual intervention. Test it with:

sudo certbot renew --dry-run

A successful dry-run is a strong signal the scheduled renewal will also work.

Frequently asked questions

Why does Let’s Encrypt fail with laravel htaccess well-known being redirected?

Because Let’s Encrypt’s HTTP-01 challenge writes a token into /.well-known/acme-challenge/ and expects to fetch it back over HTTP. Your Laravel .htaccess rewrite into public/ forwards that request to Laravel’s router, which doesn’t know the route and returns a 404. Certbot sees the 404 (or a Laravel error page) and reports Invalid response from http://example.com/.well-known/acme-challenge/.... The fix is one more RewriteCond that excludes /.well-known/ from the forwarding.

Does this change affect anything other than Let’s Encrypt?

It exposes the entire /.well-known/ path tree directly — meaning the web server serves files out of it without Laravel’s router seeing them. /.well-known/ is a reserved IANA namespace for exactly this kind of use (ACME challenges, security.txt, apple-app-site-association), so this is the correct behavior. Files you don’t put in that directory are never served from it.

Where should the .well-known folder actually live?

In your Laravel project root, alongside the public/ folder and the .htaccess file. Certbot writes the challenge token there, and with the RewriteCond excluding /.well-known/, Apache serves the file directly from that path. If the folder doesn’t exist when certbot runs, certbot creates it. After issuance the folder can be left in place — it’s only populated during a challenge.

What if I’m using nginx instead of Apache?

Nginx doesn’t use .htaccess. The equivalent is a location block in the server config: location ^~ /.well-known/acme-challenge/ { root /var/www/example.com; try_files $uri =404; }. Place it above your existing location / that forwards to index.php. The ^~ modifier ensures this location wins over regex location matches.

Can certbot auto-renew through a rewrite like this?

Yes — the certbot renew cron job uses the same HTTP-01 challenge, and as long as the .well-known exclude stays in .htaccess, renewal keeps working with no further changes. Test it with certbot renew --dry-run; if that passes, the scheduled renewal will too.

Related guides

  • Fix 403 Forbidden on Laravel Shared Hosting — the base .htaccess rewrite this post extends.
  • How to Fix cURL Error 60 SSL Certificate Problem in Laravel — the outbound side of TLS.
  • How to Install Laravel on Ubuntu — a fresh Laravel 11 install where .htaccess shows up.
  • Step-by-Step Guide to Upgrading the Linux Kernel in CentOS 7 — sibling server-management reference.

References

Let’s Encrypt HTTP-01 challenge spec: letsencrypt.org/docs/challenge-types. Apache mod_rewrite reference: httpd.apache.org/docs/current/mod/mod_rewrite.

TAGGED:ApacheconfigurationLaravelSecuritytroubleshooting

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article Laravel Vite combine CSS — @import chain bundles vendor and app stylesheets How to Compile Multiple CSS into One CSS with Laravel + Vite
Next Article Laravel run project from GitHub — git clone through artisan serve pipeline How to Run a Laravel Project from GitHub
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow

Subscribe Now

Subscribe to our newsletter to get our newest articles instantly!
Most Popular
Display PHP errors — ini_set + php.ini configuration
How to Display PHP Errors
May 10, 2026
PHP convert string to uppercase — strtoupper and mb_strtoupper
How to Convert a String to Uppercase in PHP
May 10, 2026
PHP string to float conversion with cast, regex cleanup, NumberFormatter
How to Convert a String to Float in PHP
May 10, 2026
PHP merge arrays without duplicates — union operator and array_unique
How to Combine Two Arrays Without Duplicates in PHP
May 10, 2026
PHP delete array element — unset, array_splice, array_filter, array_search
How to Delete an Element from a PHP Array
May 10, 2026

You Might Also Like

Deleting a Laravel user cascades to remove related posts, photos, and notifications
Web Development

How to Delete Related Records in Laravel Eloquent

6 Min Read
Return or throw an error in Laravel (JSON response vs exception)
Web Development

How to Manually Return or Throw an Error Exception in Laravel

6 Min Read
Laravel unknown column CONCAT fix — DB::raw and selectRaw bypass identifier escaping
Web Development

How to Fix “Unknown column ‘CONCAT'” in Laravel

8 Min Read
Laravel delete file from public folder — File::delete with public_path
Web Development

How to Delete Files from the Public Folder in Laravel

7 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Latest News

  • SEO Audit Tool
  • Client ReferralsNew
  • Execution of SEO
  • Reporting Tool

Resouce

  • Google Search Console
  • Google Keyword Planner
  • Google OptimiseHot
  • SEO Spider

Get the Top 10 in Search!

Looking for a trustworthy service to optimize the company website?
Request a Quote
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?