`kamal setup` fails on a fresh server when an accessory has a `proxy` block and `error_pages_path` is set
First: thank you for Kamal. We run our whole product on it and it has been a joy. We hit one ordering issue during a server migration and we want to report it clearly. We may be missing something - if so, we are happy to learn the intended flow.
Summary
On a brand-new server, kamal setup fails before the app boots when the config has both:
error_pages_pathset, and- an accessory with a
proxysection.
The accessory registration fails with:
Error: unable to load error pagesReproduction
Kamal 2.12.0. A minimal config shape:
error_pages_path: public
accessories:
streams:
image: alpine:latest
host: 10.0.0.1
proxy:
host: app.example.com
path_prefix: "/v1/streams"
app_port: 4437Run kamal setup against a server that has never had a deploy. Setup fails at accessory:boot.
What we think happens
In Kamal::Cli::Main#deploy (with boot_accessories: true, which setup uses), the order is:
proxy:bootaccessory:boot allapp:boot
The error pages upload to the proxy directory during step 3 (cli/app/error_pages.rb). But step 2 already passes --error-pages=<dir>/<version> when it registers the accessory with kamal-proxy, and kamal-proxy validates that the directory exists at registration time. On a fresh server the directory does not exist yet, so step 2 fails and setup stops. Step 3 never runs.
The failure needs all three conditions at once: a proxied accessory, a set error_pages_path, and a server with no prior deploy. A server that had any earlier deploy has the directory, so the problem hides on existing machines and appears only on new ones.
A second, smaller interaction: kamal app boot prunes the error-pages directories of other versions. app boot resolves its version from the deployed marker while deploy and accessory commands resolve it from git. When these differ, a later accessory boot/start can reference a directory that the prune just removed, and the same error returns on a server that has deployed fine.
Workaround we use
We replaced kamal setup on fresh servers with an explicit order:
kamal server bootstrap
kamal accessory boot <each accessory without a proxy block>
kamal deploy
kamal accessory boot <each accessory with a proxy block>This works reliably.
Possible directions
We do not know the internals well enough to say which fix fits best. Two ideas, in case they help:
- boot accessories with a
proxysection afterapp:bootinside setup, or - let the accessory registration tolerate a missing error-pages directory and fall back to default error pages.
Thanks again for the tool and for reading this far.
Source: basecamp/kamal