Recovery
Get back in when sign-in or email stops working.
What to do when a Bouée installation stops letting people in, or stops sending mail. Commands assume the
Compose setup from the README, run from the directory that holds compose.yaml and .env.
After any change to .env, recreate the web container so it reads the file again:
docker compose --profile app up -dStart with the server log. Every start prints the address Bouée answers at, and a warning for each part of the configuration that will not work the way it reads:
docker compose --profile app logs web | grep -E '\[(config|setup|storage|auth)\]'Before setup, APP_URL/preflight checks the same things and says what to fix. After it, staff see those checks
in full on Instance status (/instance/status), with what each background job last did. See
Preflight and Instance status.
Nobody can sign in because email is broken
Agents sign in with a code sent by email, and there is no password to fall back on. So when mail breaks, everyone is locked out, including the staff who would repair it. The usual causes:
- the Resend connection was disconnected, or its grant was revoked from Resend's side;
- the sending domain's DNS records were changed or removed, so Resend refuses the mail;
BETTER_AUTH_SECRETwas changed whileSECRET_ENCRYPTION_KEYwas unset, so the stored Resend credentials can no longer be decrypted (see below).
The sign-in page says so when this installation's email connection is not usable.
Emergency sign-in for staff
OWNER_SIGN_IN_CODES_TO_LOG makes Bouée write each sign-in code requested for a staff member to the
server log, as well as emailing it.
-
Add it to
.env, then recreate the web container:OWNER_SIGN_IN_CODES_TO_LOG="1"The log now opens with a warning that the setting is on.
-
Open
APP_URL/login, enter a staff member's address and select Send verification code. -
Read the code from the log. It is valid for 10 minutes, and only the newest code works:
docker compose --profile app logs web | grep 'sign-in code for staff member' -
Enter it and sign in. On Instance settings (
/instance/settings), select Reconnect Resend (or Connect Resend) under Mail delivery, check the sending domain, and use Send test to confirm that mail leaves again. -
Remove
OWNER_SIGN_IN_CODES_TO_LOGfrom.envand recreate the web container.
Anyone who can read the server log while this is on can sign in as a staff member. Treat it as a temporary key and keep the window short:
- Only an existing staff member's code is logged: an account that is already staff and is not
blocked. Agents, blocked people and addresses with no account get nothing in the log, and an address that
may not sign in at all is sent nothing, as usual. Listing an address in
OWNER_EMAILSdoes not make its code appear here until that account has become staff. - The codes are the ordinary ones: 10 minutes, five wrong guesses, one use, and requests are rate limited.
- The log is often readable by more people than the server:
docker logsaccess, a log shipper, a hosted log service, a support bundle. If your logs leave the host, assume a code written there can be read elsewhere, and turn the setting off as soon as you are in. Codes already written stop working after 10 minutes or once a newer code is requested. - While it is on, every start of the server says so in the log.
Bouée cannot read its stored credentials
The Resend connection, each workspace's inbound webhook signing secret and each brand's company sign-in
client secret are stored encrypted with SECRET_ENCRYPTION_KEY, or, while that is empty, with a key
derived from BETTER_AUTH_SECRET. Production warns at every start while SECRET_ENCRYPTION_KEY is empty.
If BETTER_AUTH_SECRET was changed and the old value is still at hand, list the old value as a decryption
key after a new one, and everything stored opens again:
SECRET_ENCRYPTION_KEY="<new key from openssl rand -base64 32>,<the previous BETTER_AUTH_SECRET>"If the old value is gone, the credentials have to be issued again: sign in (with the emergency sign-in above
if needed), reconnect Resend on /instance/settings, select Recreate webhook for each workspace's incoming email,
and paste each company sign-in client secret again. Changing BETTER_AUTH_SECRET also signs everyone out.
Encryption at rest explains the keys and how to rotate them.
Sign-in says "Invalid origin", or pages answer 404
Agent sign-in, setup and the console answer only at APP_URL, scheme, host and port included. Any other
hostname reaching Bouée serves a brand's help center, or 404 when no brand holds it. Opened there, sign-in,
setup and the console answer 404 too, and a browser is shown This address isn’t served here. That page
names neither APP_URL nor the address it was opened at, because a brand's visitors can reach it as well.
- Open the address in
APP_URLexactly, not the server's IP or a tunnel. The sign-in page names that address when a sign-in is refused for coming from another one. - The log's first
[config]line names the address Bouée believes it has. If it is wrong, correctAPP_URLin.envand recreate the web container. AnAPP_URLthat is unset, on localhost or plain http is warned about at every start in production. - The reverse proxy has to pass the original
Hostheader through. A proxy that rewrites it to127.0.0.1:3000makes every page look like a different hostname.
The server stops at startup
BETTER_AUTH_URL is …, but APP_URL is …: sign-in is served atAPP_URL, and an older env file still names a different auth address. DeleteBETTER_AUTH_URLfrom.env(or make itAPP_URL's address) and start again.Invalid environment, logged at startup and on every request while the server keeps running: the message names each variable that is missing or not accepted. Production refuses example and short secrets.
The setup link does not open setup, or is lost
-
While setup is open, the link is printed when the server starts, and again when
/setupis opened (at most once a minute):docker compose --profile app logs web | grep 'Setup link'Its token is generated once and stored, so every replica prints the same link, however many start together, and a restart prints it again rather than a new one. With
SETUP_TOKENset, the link isAPP_URL/setup#token=followed by that value. In production aSETUP_TOKENweaker than about 60 bits is ignored, and the log says so. -
A link that no longer works is an old one: a database reset stores a new token. Use the newest
Setup linkline. -
Setup has to be completed at
APP_URL; on any other address it stops before checking the link and names the address to open. On plain http whenAPP_URLis https, the browser drops the setup session, and setup says so: open the https address. -
After ten wrong tokens from one address, wait fifteen minutes.
The only staff member is gone
With mail working, add a new address to OWNER_EMAILS in .env and recreate the web container: that
address may sign in, and becomes staff when its account is created or at its next sign-in.
With mail broken as well, make an existing account staff in the database, then use the emergency sign-in above:
docker compose exec db psql -U bouee -d bouee -c "UPDATE \"User\" SET role = 'OWNER' WHERE email = 'you@example.com'"Attachments fail
The object store is tried once at every start. A [storage] WARNING line names the bucket, the endpoint and
why it refused: check S3_ENDPOINT, S3_BUCKET, S3_REGION, S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY.
The health check deliberately does not cover storage, so the rest of the help desk keeps working meanwhile.
If S3_SSE_CUSTOMER_KEY is set, attachments written under it open only with that exact key; see
Encryption at rest.