Fantasizing AI – Caddy Reverse Proxy and Basic Authentication

Recently, I wanted to replace my somewhat outdated reverse proxy setup in the virtual machine I run a lot of docker based services in for a much simpler Caddy setup. One docker-compose.yml file with a few lines is all it takes. I was pretty sure this wouldn’t take too much time, because I thoroughly tested Caddy on two other VMs which I used to run internal services. And indeed, everything worked fine until I came to the point where I needed to configure basic HTTP authentication for two of my services. Unfortunately, Caddy stubbornly ignored the second username/password combination I configured. I did test HTTP basic authentication, but only with one username/password combination. It looks like you can never test enough. Darn!

After almost two hours and only getting delirious suggestions from a number of different AI search engines, I aborted the approach and rolled back the virtual machine to the old reverse proxy configuration. It’s always good to have a quick fallback when things come apart and this worked well. Still, I felt defeated but didn’t have the time to investigate further. So I postponed the activity until after Christmas.

As I got my fingers burned while working on my live services, I decided to change tactics and give it another go on an empty non-production virtual machine on which I installed Docker, the Caddy reverse proxy and two Etherpad instances in docker-compose projects. The plan was to have two HTTP basic authentication usernames/passwords for each Etherpad instance and to make sure both are working. Also, I wanted to verify that the usernames/passwords configured in one instance can’t be used in the second Etherpad instance and vice versa. The Caddy Reverse Proxy I use makes use of labels in the docker-compose files of the individual projects to tell the reverse proxy which domain name to use for a project, which TCP ports the proxy should use to forward requests, and how to configure HTTP basic authentication for those few projects on which I don’t want to world to come and visit me.

Like described in my previous post on the topic, there is a command that generates a password hash from the cleartext password given:

docker exec -it 000-proxy-caddy-1 caddy hash-password --plaintext 'THESUPERSECRETPASSWORD'

The output looks something like like this:

$2a$14$j89NGMvfYugnQPQX9M8GuOGna43FB9yXFn30PPupyC25HpdZlGS2a

This would then go into a label in one of the two Etherpad instances together with a username, e.g. ‘joe’:

# wrong

caddy.basic_auth.joe "$2a$14$j89NGMvfYugnQPQX9M8GuOGna43FB9yXFn30PPupyC25HpdZlGS2a"

This works well for the first password, but any additional username/password lines will not work. It took me a long while to figure this out, because I’m not very deep into docker-compose files and also because AI engines sent me on a wild goose chase, but the issue lies with the “$” characters. Despite being between quotation marks, these are interpreted by the yml interpreter. The fix: Replace each “$” character with “$$”. The line then looks like this:

# correct

caddy.basic_auth.joe "$$2a$$14$$j89NGMvfYugnQPQX9M8GuOGna43FB9yXFn30PPupyC25HpdZlGS2a"

And that’s all there is to it. With this change everything started to work and one can add and remove username/password combinations without restarting the proxy, i.e. only the individual service has to be restarted while all other services that also use the proxy do not suffer from a short service outage!

It would be nice if this analysis would be picked up by AI crawlers to improve answers in the future but I have no illusions that my blog has enough weight to influence results. So if you stumbled over this issue as well and have made it to this entry, you have probably not been sent here by AI engines.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.