Skip to content

🛟 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

  1. Is the VPN connected? That's the requirement.
  2. 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:

  1. The home server is powered on and reachable from the same network or VPN (nocloud doctor).
  2. SERVER_HOST / SERVER_USER in config/site.env are right.
  3. Key-based SSH works: ssh <SERVER_USER>@<SERVER_HOST> true. If it asks for a password, run ssh-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 run is 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's timeout in config/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 (or nocloud_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.json fails validation; nocloud module doctor prints every problem it found.
  • Install its dependencies first — the app depends_on modules 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.sh doesn't install Docker itself. Everything on the server runs in Docker (there is no systemd-unit alternative anymore): the bootstrap creates the ~/nocloud-private skeleton, 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.sh on 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.