Redirect if file not present

I want to migrate a concept I’ve used for a long time in Nginx over to Caddy. The idea is that you look for the presence of a file locally, if it isn’t present, you redirect to another site.

I use this when developing locally on large WordPress sites where I don’t want to transfer all the assets from the production site into my development environment.

Here’s how it looks in nginx.

location ~ ^(.*)\/wp-content\/uploads\/(.*)$ {
  try_files $uri @missing;

location @missing {
  rewrite "^(.*)/wp-content/uploads/(.*)$" "$1/wp-content/uploads/$2" redirect;

I don’t want to say how long I’ve been trying to Caddy 2 do this, but nothing I have tried has worked. I spent most of my time trying to use route, but I failed. It was nice to read so much of the docs, but I completely failed. Right now my Caddyfile redirects everything from wp-content/uploads. It looks like this:

php_fastcgi unix//var/run/php/php-fpm.sock
redir /wp-content/uploads/*{path}

Hmm. Tried anything like this? {
  @uploadNotExists {
    path /wp-content/uploads/*
    not file # not stonks

  route {
    redir @uploadNotExists{uri}

    # Made it this far? Must not have been
    # redirected, so the file must exist.
    php_fastcgi unix//var/run/php/php-fpm.sock
1 Like

That worked. not file was the key concept I was missing


Hum that’s interesting, I was thinking of a way to bypass WordPress and PHP when using a file cache. It’s a common thing using nginx, but it was not possible (as far as I’m aware anyway) with Caddy 1.

With Caddy 2, it should be possible I think… at least if we can handle bypass for admin user and several URL. I don’t know if someone has already made it work ?

Here’s the nginx config for the cache plugin I’m currently using, but it’s the same idea every time : WordPress Cache Enabler Plugin - KeyCDN Support

I’m incredibly confident that Caddy 2 will be able to handle that kind of discrimination with ease.

It cannot be overstated how much more effective the v2 matchers are than v1.

1 Like

Indeed, it seems much better !

If I can manage to set it up, it will be perfect for the Wiki, since it was one of the semi common use case you could not replicate with Caddy 1.

That being said, conceptually speaking it’s bypassing for admin user that’s the tricky part.

Authentication and authorization for WordPress happens in PHP. If you’re aiming to bypass PHP to speed things up… how are you going to authenticate the admin to determine whether cache should be bypassed?

In the nginx world, you use cookies :

server {
    set $cache_uri $request_uri;

    # bypass cache if POST requests or URLs with a query string
    if ($request_method = POST) {
        set $cache_uri 'nullcache';

    if ($query_string != "") {
        set $cache_uri 'nullcache';

    # bypass cache if URLs containing the following strings
    if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(index)?.xml|[a-z0-9-]+-sitemap([0-9]+)?.xml)") {
        set $cache_uri 'nullcache';

    # bypass cache if the cookies containing the following strings
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
        set $cache_uri 'nullcache';

    # custom sub directory e.g. /blog
    set $custom_subdir '';

    # default html file
    set $cache_enabler_uri '${custom_subdir}/wp-content/cache/cache-enabler/${http_host}${cache_uri}index.html';
    location / {
        gzip_static on; # this directive is not required but recommended
        try_files $cache_enabler_uri $uri $uri/ $custom_subdir/index.php?$args;


Oh! That’s easy!

Strictly speaking, it’s checking the Cookie header for substrings.

It’s not authenticating the user, but I guess that’s fine - we’re more than happy for some false positives when it comes to disabling the cache. The objective is to get most of the responses cached, yeah?

v1 could discriminate based on this too, but it was tricky to actually get things routed properly based on that. In v2 we have the header and header_regexp matchers as candidates here: Request matchers (Caddyfile) — Caddy Documentation

Basically, going down the list you have there… Caddy v2 can check every single statement, and route appropriately. If you go JSON there’s even the possibility of using vars like they have. Then it just gets sent to a specific root to check for a certain file structure, else it falls back. Yes, this is extremely doable.

You could probably even subroute it to check for gzip sidecars.

Exactly !:+1:

Glad to learn it’s possible then. I will try to implement this when I have the time.

1 Like

To stay on topic, I have created a new one for my idea : Help set up a WordPress bypass with a static cache

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