🛟 Troubleshooting
The first half of this page covers what you see as a user (in the browser or the phone app);
the second half covers what you see as the operator, on the command line. When in doubt, start
with nocloud doctor — it checks the whole installation and tells you which piece is broken.
In the browser or the app
The phone app opens blank
Almost always the VPN: turn it on and reopen the app. If it persists, delete the home-screen shortcut and add it again (Share → Add to Home Screen); the first open will ask you to sign in.
A button says "no connection to the Mac / workstation"
Functions that write (expense reclassification, refreshing quotes, the danger zone, a
connector's drop area, any "↻ Refresh" button) need the machine the database lives on to be
powered on — and the daemon running on it (nocloud daemon, see
The platform). Turn it on and try again. Read-only pages don't need it.
I'm seeing stale data
- Web: reload (the server forces revalidation; no need to clear cache).
- App: fully close it and reopen; if it persists, remove the shortcut and add it again.
- Quotes: outside market hours the last close is shown — that's expected.
I can't reach NoCloud from outside the house
- Is the VPN connected? That's the requirement.
- If the VPN won't connect, your home's public IP may have changed: dynamic DNS corrects it automatically every 5 minutes — wait and try again.
The login won't let me in
- Check your SSO username/password; after several failed attempts there's a brief courtesy lockout.
- The browser session and the installed app's session are independent: sign in to each separately.
A page looks unstyled or half-rendered
Usually a partial deployment. Rebuild and republish: nocloud deploy from the workstation.
The validation email never arrives
It's only ever delivered to mailboxes hosted on your own server (your domain). Check the spam folder
too; the sender is nocloud@….
On the command line (operator)
can't find the installation at … — run: nocloud init
The launcher can't find the checkout. Either you haven't run nocloud init yet, or
~/.config/nocloud/home (or the NOCLOUD_HOME variable) points at a directory that no longer
exists. Run nocloud init, or fix the pointer:
cat ~/.config/nocloud/home # where the launcher thinks the install lives
nocloud home # what it resolved to
missing config/site.env (copy config/site.env.example and fill it in)
nocloud deploy and nocloud security need the instance configuration. Run nocloud setup (it
detects your network and writes the file, keeping any previous one as site.env.bak), or copy
config/site.env.example and fill it in by hand. Validate the result:
nocloud config check
config check flags each key as ok / warning / failure: an unknown key isn't in
config/schema.yaml, and a type error (integer, URL, email, host) tells you which format the value
must have. See the configuration reference.
✗ db_seed FAILED or ✗ gen_… FAILED during nocloud build
Almost always the database: it's missing or unseeded, and the page generators fail with
sqlite3.OperationalError: no such table …. Initialize it and rebuild:
"$(nocloud home)/.venv/bin/python3" "$(nocloud home)/scripts/db_seed.py" --init
nocloud build
nocloud init does this automatically on a fresh install; you only hit it if the database file
(local/db/nocloud.sqlite) was deleted or the checkout was copied without it.
· system/users/help skipped (nocloud-store not found at …)
Informational, not an error: those pages live in the companion nocloud-store repository. Clone it
next to the core checkout (or point NOCLOUD_STORE_DIR at it) and rebuild.
server not reachable during nocloud deploy
The workstation can't SSH into the home server. Check, in order:
- The home server is powered on and reachable from the same network or VPN (
nocloud doctor). SERVER_HOST/SERVER_USERinconfig/site.envare right.- Key-based SSH works:
ssh <SERVER_USER>@<SERVER_HOST> true. If it asks for a password, runssh-copy-id <SERVER_USER>@<SERVER_HOST>— deploy uses batch mode and never types passwords.
A deploy interrupted halfway leaves a partially published site; running nocloud deploy again is
always safe.
The daemon won't start: Address already in use
Another process (usually a previous daemon) is already listening on the port (default 8765). Find it and stop it, or start on another port:
lsof -i :8765
nocloud daemon --port 8766
If you change the port, update MAC_DAEMON_URL in config/site.env to match.
The daemon answers 401 unauthorized
NOCLOUD_DAEMON_TOKEN is set, so every request must carry it:
curl -H "Authorization: Bearer $NOCLOUD_DAEMON_TOKEN" http://127.0.0.1:8765/api/health
A job won't run: "already running" or timeout
- A job that is still running holds a lock; a second
jobs runis refused until it finishes. If the process died and the lock survived (rare), the platform clears stale locks automatically on the next attempt. - A run recorded as
timeout(return code 124) exceeded the job'stimeoutinconfig/jobs.yaml(default 900 s). Raise it if the job legitimately needs longer.
Inspect what happened with nocloud jobs history <id>.
A doctor check fails
Each ✗ line in nocloud doctor maps to one fix:
| Check | What to do |
|---|---|
git / python |
install the missing tool so it's on PATH |
runtime.yaml / jobs.yaml |
the repo files are missing — restore the checkout (nocloud update) |
config/site.env |
run nocloud setup |
config schema |
run nocloud config check for the per-key detail |
sqlite catalog / seeded sections |
run db_seed.py --init (see the build entry above) |
| jobs with recorded failures | nocloud jobs history <id>, fix the cause, re-run |
module manifests |
nocloud module doctor lists each manifest error |
backup live files |
a required item in config/backup_manifest.yaml is missing on the live system |
backup snapshot |
the backup destination has no fresh, intact snapshot — plug the backup disk in, set BACKUP_DEST in config/site.env, or check the backup_local.sh launchd job |
upgrade lifecycle |
config/upgrade.yaml is missing from the checkout |
integration adapters |
nocloud integrations check shows which adapter is failing |
nocloud doctor passes but something's still wrong
doctor checks the installation's shape (files, config, schema) — it won't catch a job that ran
and failed, or a service that's up but misbehaving. Two more places to look:
nocloud events [--limit N]— the platform's own event stream (job runs, drift detections, upgrade steps, HTTP errors); often shows exactly what happened and when.journalctl -u dovecot/journalctl -u wg-quick@wg0— logs for the two services that run natively on the home server (not in Docker).docker logs nocloud_settings_api(ornocloud_authelia,nocloud_permissions_api,nocloud_ingest_api, …) for anything containerized.
nocloud onboard says it doesn't recognize the folder
onboard only ingests what it can identify: a folder of photos/videos, or an export that matches
an installed (or installable) Store app — WhatsApp and Google Takeout exports today. Anything else
is refused rather than guessed at; install the matching connector from the Store first. Everything
onboard copies is journaled and reversible (scripts/journal.py revert <op_run>).
Module install fails: invalid manifest or dependency order
- Invalid manifest — the app's
manifest.jsonfails validation;nocloud module doctorprints every problem it found. - Install its dependencies first — the app
depends_onmodules you haven't installed; install those first (there is deliberately no cascade install). - Uninstall its dependents first — another installed module depends on the one you're removing.
If an install fails during its database migration, a snapshot was taken first; the error message
names it, and scripts/dbsafe.py restore … --latest brings the database back.
nocloud upgrade stops at preflight
Preflight refuses to proceed with a dirty git tree, a failing doctor, or a missing backup item.
nocloud upgrade preflight --json shows exactly which gate failed. --allow-dirty overrides the
git check when you're intentionally carrying local changes.
Something on the server (bootstrap)
python3 not found/docker not found— install them first;bootstrap_server_docker.shdoesn't install Docker itself. Everything on the server runs in Docker (there is no systemd-unit alternative anymore): the bootstrap creates the~/nocloud-privateskeleton, instantiates each service's compose project and brings them up; the first deploy from the workstation converges the rest — see docs/manual/installation.md.- "checkout incomplete" — the script needs the repo at
~/nocloud-core; rsync it from the workstation as the message shows, then re-run. - The security panel can't tell the egress firewall's mode — the read-only sudoers grant is
missing; run
scripts/setup_server.shon the server.
I edited nginx (or another reverse proxy) config and reloaded, but the change isn't live
A config reload re-reads the config file as the running process currently sees it — if
you're on a container/VM setup where the config file is bind-mounted, an in-place rewrite (most
editors, and sed -i, replace the file via a temp-file-then-rename rather than writing in place)
can leave the running container looking at a now-stale mount reference. The symptom is confusing
because it looks like a routing bug (a URL that should proxy somewhere now serves the wrong
content, e.g. falling through to a catch-all) rather than a stale-config bug.
Don't trust nginx -t (syntax check on the file on disk) or a "successful" reload alone — verify
what's actually loaded in memory:
docker exec <container> nginx -T | grep "<the thing you just changed>"
If that doesn't show your edit, a reload won't fix it — the container needs to remount:
docker restart <container>
docker exec <container> nginx -T | grep "<the thing you just changed>" # confirm before moving on
A background job/service didn't follow when I renamed or moved my installation directory
Anything scheduled outside the app itself (a systemd user unit, a macOS LaunchAgent, a cron entry) has the old path baked into it at the time you created it — renaming or moving the checkout doesn't retroactively update jobs that already exist. The symptom looks unrelated to the move: a page silently shows stale data, or a scheduled refresh "does nothing," because the job is quietly still running against the old location, if it still exists at all.
# macOS
grep -rl "$OLD_PATH" ~/Library/LaunchAgents/com.*.plist
# Linux
grep -rl "$OLD_PATH" ~/.config/systemd/user/*.service
Update the path in each match and reload that job (launchctl bootout+bootstrap, or
systemctl --user daemon-reload), rather than assuming a rename anywhere in the stack is free.
A change I made against the server's own copy of the database didn't stick
If your setup replicates a database from a primary machine to a server on a schedule (rather than the server being the one source of truth), any write made directly against the server's local copy is only as durable as the time until the next replication — it gets silently overwritten, with no error, the next time the sync runs. This is easy to hit by accident if a service running on the server has write access to its own local copy: it looks like it worked (no error, the change is there if you check immediately), then reverts on its own with no obvious trigger.
If your architecture has one authoritative side, route writes through it explicitly (a queue the authoritative side drains, an API call back to it) rather than writing to the local copy directly — the fix is architectural, not a retry.
Port map
Every default port (daemon 8765, Immich 2283, webmail 8888, the server's native APIs 9092/9093/9095…) is listed in the configuration reference.