HTTP Basic Auth That Actually Stays On
basic_auth: is enforced at the Caddy layer, persisted to state so it survives every future route rebuild — including the bug where it silently stopped applying.
Adding basic auth
basic_auth:
user: admin
password: "${NEO_BASIC_AUTH_PASSWORD}"
bypass:
- /api/*
- /webhooks/*
Enforced entirely at Caddy — the app container never sees it, and bypass: paths skip auth entirely (useful for a webhook endpoint that can't send a browser-style credential prompt).
Secrets via ${VAR} interpolation
The password above is resolved at deploy time from your merged environment — env:, env_file, --env, then the OS environment — so the real password lives in a gitignored env_file, not in .neo.yml itself. ${VAR:-default} works too, for a fallback when the variable isn't set.
Why it's persisted to server state
Basic auth used to live only in the live Caddy config. Running neo domain to add a second domain, or neo caddy update to refresh the proxy image, rebuilt the route from scratch — and silently dropped auth in the process, since nothing told those commands it should be there. It's now saved in /etc/neo/state.json alongside the app, and every route rebuild reapplies it from there.
The bug this tutorial exists to explain
Adding basic_auth to an app that already had a route could leave the site open. Caddy keeps route IDs unique; a plain "add" over an existing route either errored or left the old, unauthenticated route serving traffic ahead of the new one — while Neo reported success. Route creation now always replaces rather than stacks.
If you suspect a server is affected (deployed before this fix, added basic_auth to an existing app):
neo caddy routes # AUTH column shows what's ACTUALLY being enforced
neo caddy reload --app my-app # rebuilds the route from state — no redeploy needed
none in the AUTH column means the live route has no auth handler regardless of what .neo.yml says — neo caddy reload fixes it immediately.
Env changes apply auth too
A neo env set restart used to skip reapplying basic_auth even when the password had changed — it now re-resolves and reapplies auth on every env-triggered restart, not just on a full deploy.
Try it yourself — Neo is free, with every feature unlocked.
Get started free