Trying to convert Caddyfile v1 to v2 : errors handler with an HTML page

1. Caddy version (caddy version):

(devel)

2. How I run Caddy:

systemctl start caddy

a. System environment:

Archlinux ARM. Package from AUR: https://aur.archlinux.org/packages/caddy2/

b. Command:

systemctl start caddy

c. Service/unit/compose file:

[Unit]
Description=Caddy Web Server
Documentation=https://caddyserver.com/docs/
After=network.target

[Service]
User=http
Group=http
ExecStart=/usr/bin/caddy run --config /etc/caddy/Caddyfile --watch --environ
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
ExecStop=/usr/bin/caddy stop
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512

# Hardening options
PrivateTmp=true
ProtectSystem=strict
PrivateDevices=true
ProtectHome=true
ReadWritePaths=/var/lib/caddy /var/log/caddy /srv/http
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
LockPersonality=true

[Install]
WantedBy=multi-user.target

d. My complete Caddyfile or JSON config:

http://torrent.local {
        root * /var/lib/caddy/web-wol
        file_server
        reverse_proxy / [fe80::7ae3:b5ff:fe92:84ed]:3000
        reverse_proxy /poweron [::1]:8888
}

3. The problem I’m having:

I’m trying to display a custom HTML page when there is a 502 HTTP error but I can’t find this functionality on Caddy v2.

Here is my Caddyfile v1:

http://torrent.local {
        root /var/lib/caddy/web-wol
        errors {
                502 502.html
        }
        proxy / [fe80::7ae3:b5ff:fe92:84ed]:3000 {
                timeout 5s
                try_duration 5s
                transparent
        }
        proxy /poweron [::1]:8888
}

4. Error messages and/or full log output:

May 21 12:37:05 odroidhc1 caddy[14927]: caddy.HomeDir=/srv/http
May 21 12:37:05 odroidhc1 caddy[14927]: caddy.AppDataDir=/srv/http/.local/share/caddy
May 21 12:37:05 odroidhc1 caddy[14927]: caddy.AppConfigDir=/srv/http/.config/caddy
May 21 12:37:05 odroidhc1 caddy[14927]: caddy.ConfigAutosavePath=/srv/http/.config/caddy/autosave.json
May 21 12:37:05 odroidhc1 caddy[14927]: runtime.GOOS=linux
May 21 12:37:05 odroidhc1 caddy[14927]: runtime.GOARCH=arm
May 21 12:37:05 odroidhc1 caddy[14927]: runtime.Compiler=gc
May 21 12:37:05 odroidhc1 caddy[14927]: runtime.NumCPU=8
May 21 12:37:05 odroidhc1 caddy[14927]: runtime.GOMAXPROCS=8
May 21 12:37:05 odroidhc1 caddy[14927]: runtime.Version=go1.14.2
May 21 12:37:05 odroidhc1 caddy[14927]: os.Getwd=/
May 21 12:37:05 odroidhc1 caddy[14927]: LANG=en_US.UTF-8
May 21 12:37:05 odroidhc1 caddy[14927]: PATH=/usr/local/sbin:/usr/local/bin:/usr/bin
May 21 12:37:05 odroidhc1 caddy[14927]: HOME=/srv/http
May 21 12:37:05 odroidhc1 caddy[14927]: LOGNAME=http
May 21 12:37:05 odroidhc1 caddy[14927]: USER=http
May 21 12:37:05 odroidhc1 caddy[14927]: INVOCATION_ID=195361a7a11e4edd8cb01c0b80e326e6
May 21 12:37:05 odroidhc1 caddy[14927]: JOURNAL_STREAM=8:6191739
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"info","ts":1590057425.133095,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":""}
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"info","ts":1590057425.1457064,"logger":"admin","msg":"admin endpoint started","address":"tcp/localhost:2019","enforce_origin":false,"origins":["[::1]:2019","127.0.0.1:2019","localhost:2019"]}
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"info","ts":1590057425.1464849,"logger":"http","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"info","ts":1590057425.146551,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"info","ts":1590057425.1466107,"logger":"http","msg":"server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server","server_name":"srv1","http_port":80}
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"warn","ts":1590057425.1466866,"logger":"http","msg":"user server is listening on same interface as automatic HTTP->HTTPS redirects; user-configured routes might override these redirects","server_name":"srv1","interface":"tcp/:80"}
May 21 12:37:05 odroidhc1 caddy[14927]: 2020/05/21 12:37:05 [INFO][cache:0x25bd000] Started certificate maintenance routine
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"info","ts":1590057425.1578522,"logger":"tls","msg":"cleaned up storage units"}
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"info","ts":1590057425.158264,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["doh.unixfox.eu"]}
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"info","ts":1590057425.16126,"msg":"autosaved config","file":"/srv/http/.config/caddy/autosave.json"}
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"info","ts":1590057425.1613092,"msg":"serving initial configuration"}
May 21 12:37:05 odroidhc1 caddy[14927]: {"level":"info","ts":1590057425.1614885,"logger":"watcher","msg":"watching config file for changes","config_file":"/etc/caddy/Caddyfile"}

5. What I already tried:

I tried to find an http.matchers for status code and make it so it display my custom HTML page when there is a 502 HTTP error but I didn’t find that in the docs.

6. Links to relevant resources:

In Caddy v2, path matching is exact match. This means that /poweron will only match requests to /poweron but not /poweron/foo. Instead, you need to append a * to the path to match the rest. This is described in the upgrade guide:

You should also omit the / from your first reverse_proxy for the same reason. If your remove it, it defaults to * which matches all paths.

Currently, handling errors is a bit tricky. We have plans to improve that soon. For now, this should do what you need though:

handle_errors {
	@502 {
		expression {http.error.status_code} == 502
	}
	handle @502 {
		root * /var/lib/caddy/web-wol
		rewrite 502.html
		file_server
	}
}

The handle_errors directive is essentially its own set of directives that get used if an error is encountered. Its handling is isolated from the rest of the handling. I’m sure we’ll figure out a shorter way to do the same thing in a future release of Caddy.