Install
export CADDY_VERSION=2.9.1
wget https://github.com/caddyserver/caddy/releases/download/v${CADDY_VERSION}/caddy_${CADDY_VERSION}_linux_amd64.tar.gz
tar zxf caddy_${CADDY_VERSION}_linux_amd64.tar.gz
# arm
wget https://github.com/caddyserver/caddy/releases/download/v${CADDY_VERSION}/caddy_${CADDY_VERSION}_linux_arm64.tar.gz
tar zxf caddy_${CADDY_VERSION}_linux_arm64.tar.gz
# check
./caddy version
# move to bin
sudo mv ./caddy /usr/local/bin/
# check again
caddy version
# clean unneccessary file
rm caddy_${CADDY_VERSION}_linux_amd64.tar.gz
rm caddy_${CADDY_VERSION}_linux_arm64.tar.gz
Createa Caddyfile
sudo mkdir -p /etc/caddy/sites
sudo vim /etc/caddy/Caddyfile
Caddyfile
{
# debug
email admin@pwshub.com
servers :443 {
protocols h1 h2c h3
}
}
:80 {
root * /workspace/html/default
file_server
encode gzip
header server "PrivEngine/2.1"
header X-Forwarded-For $proxy_add_x_forwarded_for
header Host $host
header Upgrade $http_upgrade
header Connection "upgrade"
header {
Strict-Transport-Security max-age=31536000;
X-Content-Type-Options nosniff
X-Frame-Options DENY
Referrer-Policy no-referrer-when-downgrade
}
handle_errors {
respond "{err.status_code} {err.status_text}"
}
log {
format json
output file /workspace/runtimes/logs/caddy/default/access.log {
roll_size 10mb
roll_keep 7
roll_keep_for 168h
}
}
}
import sites/*.caddy
Create service
sudo vim /etc/systemd/system/my-caddy.service
caddy.service
[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target
[Service]
Type=notify
User=ndaidong
Group=ndaidong
ExecStart=/usr/local/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
#LimitNOFILE=1048576
#LimitNPROC=512
#PrivateTmp=true
#ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE
#RuntimeDirectory=caddy
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable my-caddy.service
sudo systemctl start my-caddy.service
sudo systemctl status my-caddy.service
Use docker
mkdir /opt/engines/caddy
cd /opt/engines/caddy
vim docker-compose.yaml
docker-compose.yaml
services:
caddy:
image: caddy:2.9.1-alpine
container_name: caddy
ports:
- 80:80
- 443:443
volumes:
- ./storage/Caddyfile:/etc/caddy/Caddyfile
- ./storage/sites:/etc/caddy/sites
- ./storage/logs:/workspace/runtimes/logs
- ./storage/html:/workspace/html/default
- ./storage/data:/data
- ./storage/config:/config
restart: unless-stopped
Ensure there is index.html
and favicon.ico
within ./site
as they will be loaded as default site.
Reload config:
docker-compose exec -w /etc/caddy caddy caddy reload
View logs:
docker-compose logs caddy -f
Reverse proxy optimization
:80 {
tls {
protocols tls1.2 tls1.3
}
# Set up timeouts
timeouts {
read 30s # Time to allow for reading the request
write 30s # Time to allow for writing the response
idle 5m # Time to allow for an idle connection
}
# Limit the number of simultaneous connections
limits {
max_conns_per_ip 10
max_reuse 25
}
# Caddyfile snippet demonstrating HTTP caching headers
@cacheable {
path *.css *.js *.jpg *.jpeg *.png *.gif *.webp *.svg
not header Cache-Control *no-cache*
}
header @cacheable Cache-Control "max-age=5184000"
# Caddyfile snippet with reverse proxy cache
reverse_proxy / localhost:9000 {
header_up Host {host}
header_up X-Real-IP {remote}
header_up X-Forwarded-For {remote}
header_up X-Forwarded-Port {server_port}
header_up X-Forwarded-Proto {scheme}
cache {
ttl 30m # Time to live for cached content
max_size 300MB # Maximum size of the cache
}
to server1:9000 server2:9000
lb_policy least_conn
}
cache {
match_path /public/*
default_max_age 30m
}
}
Basic Auth
Generate crypted password
caddy hash-password -p PASSWORD -a ALGORITHM
Available algorithm: bcrypt
→ this is default
Example:
caddy hash-password -p YOUR_PASS
Set basic auth
example.com {
basic_auth {
ndaidong GENERATED_HASH
}
respond "Welcome, {http.auth.user.id}" 200
}
Protect files in /secret/
so only ndaidong
can access them (and anyone can see other paths):
example.com {
root * /srv
basic_auth /secret/* {
ndaidong GENERATED_HASH
}
file_server
}
Caddy for local dev
Setup HTTPS for local server
Install caddy to get caddy
command, and:
sudo apt install libnss3-tools
Configure host file
sudo vim /etc/hosts
// add a new line
127.0.0.1 mydomain.local
Use command line
sudo caddy reverse-proxy --from mydomain.local --to :8000
Use config file
{
debug
}
mydomain.local {
reverse_proxy 0.0.0.0:8000
encode gzip
header server "PrivEngine/2.0"
header X-Forwarded-For $proxy_add_x_forwarded_for
header Host $host
}
sudo caddy run --config ./Caddyfile
Reverse proxy with Rewrite
Source
https://extractus.local/feed/parse?query
Target
http://localhost:8001/extract?query
Here we forward a request from extractus.local/feed/parse
to localhost:8001/extract
, different host and path
extractus.local {
rewrite /feed/parse /extract
@feed {
method GET
path /extract
}
reverse_proxy @feed 0.0.0.0:8001
encode gzip
header server "PrivEngine/2.0"
header X-Forwarded-For $proxy_add_x_forwarded_for
header Host $host
}
GoAccess log
static
cat /workspace/runtimes/logs/caddy/thucchien-dev/access.log | docker run --rm -i -e LANG=$LANG allinurl/goaccess -a -o html --log-format=CADDY - > report.html
realtime
cat ./access.log | docker run --rm -i -e LANG=$LANG allinurl/goaccess -a -o html --log-format=CADDY --real-time-html - > /workspace/html/default/report.html