Follow-up: one more config.yml directive needed to avoid Cloudron healthcheck failures
A week or so after getting our production instance working, it silently went unhealthy on us. Worth documenting for anyone else who follows this guide, because the symptom is confusing and the fix is trivial.
Symptom
The Cloudron dashboard shows the app as "not responding", or the browser shows a Cloudron error page instead of docassemble. Inside the container, everything looks healthy:
# supervisorctl status
celery RUNNING
celerysingle RUNNING
cron RUNNING
main:initialize RUNNING
nginx RUNNING
uwsgi RUNNING
websockets RUNNING
Meanwhile, the Cloudron app log fills up with this, every ten seconds, indefinitely:
=> Healthcheck error got response status 501
=> Healthcheck error got response status 501
=> Healthcheck error got response status 501
And docassemble.log shows repeated entries like:
docassemble: ip=172.18.0.1 i=docassemble.base:data/questions/default-interview.yml uid=None user=anonymous 2026-04-16 20:47:50 Not authorized
What is actually happening
Docassemble is fine. uWSGI is answering requests. The problem is that it is answering Cloudron's healthcheck probe of / with HTTP 501 NOT IMPLEMENTED.
Testing from inside the container confirms this:
# curl -sI http://localhost:8080/
HTTP/1.1 501 NOT IMPLEMENTED
Server: nginx
Content-Type: text/html; charset=utf-8
This is docassemble's deliberate behaviour when an anonymous user hits the root URL and there is no default interview set and no root redirect configured. It falls through to the factory default interview (docassemble.base:data/questions/default-interview.yml), which refuses anonymous access and returns 501 with a "Not authorized" body. There is even a dedicated /static/app/501.min.js in the response HTML, so this is a well-worn code path upstream.
Cloudron's healthcheck expects a 2xx or 3xx at the probe path. 501 trips the unhealthy marker, and after a few failed probes Cloudron stops proxying user traffic to the app. The app is then effectively offline to users even though it is running normally internally.
The fix
Add a single directive to /app/data/config/config.yml:
root redirect url: /user/sign-in
Then restart uWSGI from inside the container (via the Cloudron terminal):
supervisorctl restart uwsgi
After this, / returns a 302 redirect to /user/sign-in, which returns 200, and Cloudron's healthcheck is satisfied. The sign-in page is a sensible default landing for a private docassemble instance anyway.
Verification from inside the container:
# curl -sI http://localhost:8080/
HTTP/1.1 302 FOUND
Location: /user/sign-in
Give Cloudron 30-60 seconds to pick up the healthy state. The app will come back online in the dashboard.
Why this probably didn't bite us during the initial packaging
Best guess is an upstream behaviour change in docassemble itself. Earlier versions may have redirected anonymous root requests to the sign-in page automatically; current versions return 501 unless root redirect url or default interview (with anonymous access enabled) is explicitly set. It works on first install because the default interview loads once and caches, then fails later when cache conditions change or the app is redeployed.
Suggested addition to the packaging guide
Two options for handling this in the package itself, either of which would remove the manual step:
- Have
start.sh ensure root redirect url: /user/sign-in is present in the generated config.yml if neither root redirect url nor default interview is set by the user.
- Add it as a default to the config template, so any new install gets it on first boot.
Option 1 is safer because it will not override a user who has deliberately set one of those directives.
Happy to PR this into the repo if there is interest.