Troubleshooting & Operations
This guide groups common self-hosting issues by subsystem, explaining root causes and concrete resolutions.
Diagnostic Matrix
1. Setup & Installation
| Symptom | Probable Cause | Concrete Fix |
|---|---|---|
Node version incompatible | Node.js is older than v22. | Install Node.js 22 LTS or newer (node -v). |
pnpm install errors on lockfile | Installed using npm or yarn instead of pnpm. | Delete node_modules, run corepack enable, and install with pnpm install. |
2. API Startup & Database
| Symptom | Probable Cause | Concrete Fix |
|---|---|---|
Failed to connect Mongoose client for auth | MongoDB is unreachable or MONGO_URI is incorrect. | Ensure MongoDB is running (docker ps or systemctl status mongod) and test MONGO_URI with mongosh <MONGO_URI>. |
BETTER_AUTH_SECRET is not configured | Missing required session secret. | Generate with openssl rand -base64 32 and paste into BETTER_AUTH_SECRET in api/.env. |
Port 4000 is already in use | A dangling background process survived shutdown. | Run lsof -i :4000 to find the lingering process and terminate it with kill -9 <PID>. |
Startup warning about INTERNAL_API_SECRET | Missing or blank secret. | Generate with openssl rand -hex 32 and paste identically into both api/.env and app/.env. |
3. Authentication & Sessions
| Symptom | Probable Cause | Concrete Fix |
|---|---|---|
Login succeeds, but next request returns 401 Unauthorized | Session cookie not being sent by the browser. | Check COOKIE_DOMAIN and ensure CORS_ORIGINS includes your web origin. In development, leave COOKIE_DOMAIN unset. |
Session works on localhost, breaks on subdomains | COOKIE_DOMAIN missing leading dot. | In api/.env, set COOKIE_DOMAIN=".example.com" (with the leading dot). Note that HTTPS is mandatory when this is set. |
| No OTP email arrives at signup | No SMTP provider configured. | Look at the terminal output of the API process. Core logs the 6-digit OTP directly to stdout. Alternatively, set REQUIRE_EMAIL_VERIFICATION=false to skip email validation. |
| All users logged out after a deployment | BETTER_AUTH_SECRET was regenerated or changed. | Ensure BETTER_AUTH_SECRET remains persistent across deployments. |
4. Git Providers & Repositories
| Symptom | Probable Cause | Concrete Fix |
|---|---|---|
| GitHub App install popup 404s | NEXT_PUBLIC_GITHUB_APP_NAME in app/.env does not match the actual GitHub App slug. | Open https://github.com/apps/<name> to verify the slug. |
| Install popup completes, but nothing links | βRequest user authorization (OAuth) during installationβ was unchecked. | In GitHub App settings, check βRequest user authorization (OAuth) during installationβ and save. |
403 Forbidden on commit or tree read | GitHub App repository permissions are too narrow. | Verify that Contents (Code) and Pull requests are both set to Read & write. |
| GitHub App authentication error (signing failed) | GITHUB_APP_PRIVATE_KEY lost line breaks. | Wrap the private key in double quotes in app/.env so \n characters are preserved. |
| GitLab callback rejected | Redirect URI mismatch. | Ensure the URI in GitLab is set character-for-character to <APP_URL>/gitlab-installed. |
5. Real-Time Collaboration & WebSockets
| Symptom | Probable Cause | Concrete Fix |
|---|---|---|
| Collaboration drops immediately after connecting | Reverse proxy is not forwarding WebSocket upgrades. | Check your Nginx or Caddy configuration. Ensure Upgrade and Connection headers are forwarded for /api/v1/editor/collab and /socket.io/. |
Forbidden from Hocuspocus | User is not a member of the organization. | Hocuspocus checks isOrgMember(userId, orgId) on connection. Verify organization membership in the database. |
| Presence rosters inconsistent across users | Running multiple API server processes. | Socket.IO and Hocuspocus keep state in process memory. Run a single API instance. |
6. Media Storage
| Symptom | Probable Cause | Concrete Fix |
|---|---|---|
| Upload fails with browser CORS error | Bucket CORS rules do not permit your web origin. | Add your web app origin to the bucketβs CORS configuration. |
| Upload succeeds, but avatar shows as broken image | NEXT_PUBLIC_BUCKET_URL mismatch. | Ensure NEXT_PUBLIC_BUCKET_URL in app/.env points to the exact public domain of the bucket. |
| MinIO signature errors | Path-style gateway required. | Set S3_FORCE_PATH_STYLE=true in api/.env. |
7. Live Preview Sandboxes
| Symptom | Probable Cause | Concrete Fix |
|---|---|---|
| Preview fails for entire organization after deploy | SANDBOX_ENCRYPTION_KEY changed. | Rotating this key invalidates stored sandbox tokens. Re-input sandbox credentials in Organization Settings. |
| Preview server never reports ready (times out after 180s) | The dev server bound only to 127.0.0.1 inside the VM. | Sitepins patches scripts to --host 0.0.0.0. Ensure your framework dev command accepts external connections. |
Backup & Recovery Runbook
Website content and images are safely committed to your Git repositories. However, user profiles, organization memberships, permissions, and project settings reside in MongoDB.
1. Database Backup (mongodump)
Create an archive backup:
# Direct mongodump
mongodump --uri="mongodb://localhost:27017/sitepins" --archive="sitepins-backup-$(date +%Y%m%d).archive" --gzip
# Or from Docker container
docker compose exec -T mongo mongodump --db=sitepins --archive --gzip > sitepins-backup.archive2. Database Restore (mongorestore)
Restore from an archive backup:
# Direct restore
mongorestore --uri="mongodb://localhost:27017/sitepins" --archive="sitepins-backup.archive" --gzip --drop
# Or from Docker container
cat sitepins-backup.archive | docker compose exec -T mongo mongorestore --archive --gzip --dropThe --drop flag will erase existing collections in the target database before restoring. Use with caution in production.
Last updated on