Here is a quick guide how to set HTTP basic auth username and password using environment variables.
-
Hardcoding password, even hashed one, in
Caddyfile
, or any file, is a dangerous practice and should be avoided -
HTTP Basic Auth is an easy way to protect your development servers, other infrastructure, against scrapers, knocking, etc. even if the content behind the password does not need security otherwise
-
We show how to generate a secrets file from the command line
-
We also show how to use with Docker environment fails and their pitfalls
Caddyfile supports expanding of environment variables. Syntax is somewhat unique, so pay attention on it.
We are going to store our username and password in a file called secrets.env
. This file should not be part of any source code control and only reside on the server. You should add the file to your .gitignore
if you are using git.
We use Caddy’s docker version to the command to generate the hashed password. This environment file is Docker format as all tools have their own unique environment file format. Note that it is important to wrap variable values to ‘’ as otherwise Docker attempts to expand dollar sign.
Replace “myuser” / “mypassword” with your own username and password combination:
echo "HTTP_BASIC_AUTH_USER='myuser'" >> secrets.env
HASHED_PASSWORD=$(docker run caddy caddy hash-password --plaintext "mypassword")
echo "HTTP_BASIC_AUTH_PASSWORD='$HASHED_PASSWORD'" >> secrets.env
Now you can view the file:
cat secrets.env
HTTP_BASIC_AUTH_USER='myuser'
HTTP_BASIC_AUTH_PASSWORD='...'
Then we create a Caddyfile
that uses this configuration. We create a static file web server that runs in port 9997 and outputs index.html from a local folder. This is a good way to test that HTTP Basic Auth works, as when using file_server you eliminate other sources of problems. We also turn on various logging file that help to troubleshoot the problems.
#
# Caddy HTTP basic auth example
#
{
email no-reply@example.com
# Use the log file mapped to the host FS
log {
output file /var/log/caddy/error.log.json
format json
}
}
#
# Plain index.html server to test Caddy and basic auth.
# Listens to all IP addresses and any domain name at port 9997
#
http://:9997 {
handle {
basicauth {
{$HTTP_BASIC_AUTH_USER} {$HTTP_BASIC_AUTH_PASSWORD}
}
# Mapped in docker-compose.yml
root * /var/static
file_server browse
}
# Set the default error page
# https://caddyserver.com/docs/caddyfile/directives/handle_errors
handle_errors {
respond "{http.error.status_code} {http.error.status_text}"
}
log {
output file /var/log/caddy/access-test.log.json
format json
}
}
Then we create docker-compose.yml
that will read secrets.env
and pass it to Caddy.
version: "3"
services:
caddy:
container_name: caddy
image: caddy:2.6.4-alpine
restart: unless-stopped
# Contains BASIC_AUTH_USER and BASIC_AUTH_PASSWORD
env_file:
- secrets.env
# We directly bind to the host ports and there is no Docker network here
network_mode: host
volumes:
- $PWD/Caddyfile:/etc/caddy/Caddyfile
- $PWD/logs:/var/log/caddy # shared volume with caddy
- $PWD/static:/var/static # shared volume with caddy
Let’s also create host-mapped folders and content:
mkdir logs # Logs go here
mkdir static
echo "Hello world" > static/index.html
Now you can run this with docker-compose
:
docker-compose up caddy
Visit localhost:9997
and you get the web browser prompt for the password: