Troubleshooting
Common problems with a self-hosted Brainitive installation and how to fix them. Start with the logs: they usually name the cause.
# Docker
docker compose logs -f app queue scheduler realtime
# Manual install
tail -f /opt/brainitive/storage/logs/laravel.log
journalctl -u brainitive-queue -u brainitive-realtime -fBrainitive answers GET /up with status 200 when the app is running, which is handy for uptime monitors.
"Database not reachable"
The Docker containers wait up to two minutes for the database, then stop with Database not reachable after 2 minutes — check DB_HOST / DB_PASSWORD.
DB_PASSWORDin.envmust match the password PostgreSQL was first started with. Changing it in.envlater doesn't change it in the database. Either change it inside PostgreSQL (ALTER USER brainitive WITH PASSWORD '…';) or start over with a freshpgdatavolume (only on an installation without data).- Manual install: check
DB_HOST,DB_PORTandDB_CONNECTION=pgsql, then test withphp artisan db:show.
APP_KEY problems
- Docker: if
APP_KEYis empty, the app container generates one on first start and keeps it in the storage volume asstorage/app.key. Thequeueandschedulercontainers wait for it. If they reportAPP_KEY is missing and the app container hasn't generated one, check the app container's logs. - A key in
.envalways wins overstorage/app.key. - Manual install:
No application encryption key has been specifiedmeansAPP_KEYis empty. Runphp artisan key:generateonce, thenphp artisan optimize. Never do this on an installation with data, because a new key makes stored secrets unreadable. - Stored secrets can't be decrypted / everyone was signed out: the key changed. Put the original key back from your backup. If you rotated it on purpose, list the old one in
APP_PREVIOUS_KEYS.
Permission errors on storage
Errors like Permission denied for storage/logs/laravel.log or bootstrap/cache mean the web server user can't write there. Usually a command was run as root and created files www-data can't change.
cd /opt/brainitive
sudo chown -R www-data:www-data storage bootstrap/cache
sudo chmod -R ug+rwX storage bootstrap/cacheRun php artisan commands as sudo -u www-data php artisan … to avoid this.
Uploaded images don't show
- Manual install: run
php artisan storage:linkonce. It linkspublic/storagetostorage/app/public. - Check that
APP_URLmatches the address in the browser. Upload links are built from it.
"Your session expired" or wrong http:// links behind a proxy
If forms keep failing with Your session expired. Please try again., you get sent back to the login page, or links and redirects use http:// although the site runs on HTTPS:
- Set
APP_URLto the exact address people use, withhttps://. - Set
TRUSTED_PROXIESto your reverse proxy's IP address or network, so Brainitive trusts itsX-Forwarded-Protoheader. The Docker template trusts localhost and private networks by default. - Make sure the proxy sends
X-Forwarded-ForandX-Forwarded-Proto(see the nginx example in Docker). - Leave
SESSION_DOMAINempty unless you know you need it. - Apply the change:
docker compose up -d, orphp artisan optimizeon a manual install.
Live editing doesn't connect
Editors see Live editing unavailable — editing alone, or the bell only updates every 30 seconds.
- Is
COLLAB_URLset? Live co-editing is off while it is empty. In Docker,compose.yamlsets it to/collab. - Is the realtime server running? Docker:
docker compose ps realtime. Manual:systemctl status brainitive-realtime, andcurl http://127.0.0.1:1234/should answerWelcome to Hocuspocus!. - Does the proxy pass WebSockets?
/collabneeds theUpgradeandConnectionheaders andproxy_http_version 1.1. A502means nginx can't reach the realtime server; check the port. - Same secret?
COLLAB_SECRETmust be identical for the app and the realtime server (or unset on both, with the sameAPP_KEY). With a mismatch, the realtime server closes every connection right after it opens. - Can the realtime server reach the app? It calls
COLLAB_APP_URL(defaultAPP_URL). Large documents needclient_max_body_sizeof at least25min nginx. - Bell not instant: set
LIVE_PUBLISH_URLto the realtime server's own address, for examplehttp://127.0.0.1:1234, never the public URL.
More in Realtime server.
Emails are not sent
- Is the queue worker running? Emails are sent from the queue. Docker:
docker compose ps queue. Manual:systemctl status brainitive-queue. - Is
MAIL_MAILERstilllog? Then emails only go to the log. - Test the server: Instance admin → Settings → Send a test email shows the mail server's error right away.
- Remember the override: SMTP saved in the admin console wins over
MAIL_*in.env. - Failed jobs: Instance admin → Overview, or
php artisan queue:failed. - Sign-up or "forgot password" fails with a mail error:
MAIL_*points to a server that doesn't exist. UseMAIL_MAILER=loguntil SMTP works. - Mail lands in spam: set up SPF, DKIM and DMARC. See Email.
Reminders and digests never arrive
The scheduler isn't running.
- Docker:
docker compose ps scheduler. - Manual: check the cron entry with
sudo crontab -u www-data -l. Runphp artisan schedule:listto see the tasks andphp artisan schedule:runonce by hand to see errors.
See Queue worker and scheduler.
Search finds nothing
- The index is built by the queue worker. Check that it runs.
- After an update, the first build takes a few minutes on large installations.
- Rebuild by hand:
php artisan search:reindex. See Search.
Settings in .env have no effect
The configuration is cached.
- Docker: run
docker compose up -dafter editing.env. - Manual:
php artisan optimize, thenphp artisan queue:restartso the worker reloads too.
Web push notifications never arrive
VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY are empty. Without them, no browser can subscribe. Generate keys with php artisan webpush:vapid --show, add them and VAPID_SUBJECT to .env, apply the change, and restart the queue worker.
Uploads fail for large files
Imports and archives may be up to 200 MB. Raise the limits in your proxy (client_max_body_size 210m; in nginx) and, on a manual install, in PHP (upload_max_filesize = 200M, post_max_size = 210M). The Docker image already has these PHP limits.

