📦 Installation
Developing, not installing?
This page installs NoCloud as a user (real config, real data paths). To hack on the
code you need none of it — see CONTRIBUTING.md in the repo: a plain clone plus the test
suites, all on synthetic data.
The product has two roles: a workstation owns the archive and authoritative database, while an always-on home server serves the private portal over your own network or VPN. The full local runtime is supported on macOS and Linux; Windows users can run it through WSL. The Desktop portal client itself is available on macOS, Windows, and Linux.
1. Workstation
nocloud-core is still a private repo, so an anonymous curl against
raw.githubusercontent.com can't fetch it — clone it with an SSH key that has access instead:
git clone git@github.com:NoCloudLife/nocloud-core.git ~/nocloud && ~/nocloud/bin/nocloud init
nocloud init creates the Python environment, initializes the local database, and symlinks the
launcher onto your PATH at ~/.local/bin/nocloud (make sure that's on your PATH). A Homebrew
formula is also available via
NoCloudLife/homebrew-nocloud
(brew tap NoCloudLife/nocloud && brew install nocloud); it installs from this same private repo
over SSH (no tagged release exists yet).
Then:
- Configure:
nocloud setup— a guided, ASCII-art assistant that detects your network (your workstation's IP, router, and home server candidates on the LAN) and writes~/nocloud/config/site.envfor you. You can also edit that file by hand (server SSH host/user, service URLs, API keys) — it never travels to git either way. - Check:
nocloud doctor— 18 checks covering git, Python, the job registry, the configuration schema, the database, seeded sections, module manifests, the backup contract (both the live files it promises to copy and the freshness of the latest snapshot at the backup destination), the audit event stream, the upgrade lifecycle, the integration adapters, and (low-severity, since it's optional) whether Rule Coach's local LLM is reachable. - Bring in your data:
nocloud onboard <folder-or-export>— point it at a folder of photos/videos, a WhatsApp export or a Google Takeout export and it copies them in (reversibly — originals are never moved or edited) and builds your first populated view automatically. Anything it doesn't recognize yet (bank/tax statements, other connectors) it says so plainly rather than guessing; install the matching connector from the Store for those instead. Photos land underARCHIVE_ROOT, but Immich only shows them once, the first time: in Immich → Administration → Libraries, add an External Library pointing at your archive's photo folder. Immich scans it on its own schedule after that —onboarddoesn't (and can't) trigger Immich directly. - Follow the handoff:
nocloud journeyshows the single next action across setup, import, Immich connection and publication. The same journey also offers relevant Store apps and shows recovery or archive-drift follow-up. It appears as Getting started on Home.
2. Home server
Use a Linux host reachable over SSH with Docker Compose. It can be a mini PC, NAS, VM, or a Raspberry Pi with sufficient storage; NoCloud does not require a particular board. The one-time image pulls during setup are normal for any self-hosted box; what NoCloud avoids afterward is the home server pulling its own code from GitHub on an ongoing basis — the workstation pushes to the server over your LAN/SSH instead (see Network & outbound traffic).
Everything on the server runs in Docker, and everything lives in three directories —
~/nocloud-core (the code), ~/nocloud-private (your instance: config, secrets, service
projects) and your archive. Each service is its own small compose project under
~/nocloud-private/services/; service data (Immich's library and database) lives in named
Docker volumes.
- Copy the repo over once (from the workstation):
rsync -a --exclude=.venv ~/nocloud-core/ user@<host>:~/nocloud-core/. -
Run the bootstrap on the server (needs
dockerwith the compose plugin already installed):scripts/bootstrap_server_docker.sh --site-url=https://portal.example.com \ --admin-users=you --archive=/home/you/Archive --services=immich,homeassistant,syncthing
It creates the ~/nocloud-private/ skeleton (from nocloud-private-sample/), instantiates
each chosen service's compose project plus the product's own three APIs, records provenance
in config/services.json — a service already running on the machine is marked preexisting
and never touched; the ones NoCloud starts are managed, which is what makes a clean,
per-service uninstall possible later (scripts/uninstall_server.sh) — initializes the working
database, and brings the containers up. Re-running is always safe: it only ever fills gaps.
3. Set up the SSO admin login: the desktop app's guided setup, or by hand from the workstation —
ssh user@<host> 'bash -s' -- you you@example.com https://portal.example.com <
scripts/setup_authelia.sh. You can pass your own password as a fourth argument (10+
characters); without it a strong one is generated and shown exactly once.
4. First deploy, from the workstation: bash scripts/deploy_server.sh. Its first step is
heal_server.sh, which converges everything the bootstrap didn't create — the nginx container
and TLS, the portal content, anything missing — and every later deploy re-converges the same
way. A deleted directory on the server is something the next deploy repairs, not an incident.
Webmail (Roundcube) is genuinely optional, not just deferred — it's a live browser UI against
your IMAP account, not how mail gets into NoCloud. That happens regardless, via
scripts/mail_refresh.py (mbsync-based, appends new messages to a master Maildir by
Message-ID) — most people care far more about that ongoing history than about a browser client.
- Wire up single sign-on once Authelia is running, so Immich uses the same portal session — no
second login:
- Generate the secrets on the server: a client secret
(
docker exec nocloud_authelia authelia crypto rand --length 64 --charset alphanumeric), its PBKDF2 hash (authelia crypto hash generate pbkdf2 --password '<secret>'), and an RSA key pair to sign the tokens (authelia crypto certificate rsa generate --common-name auth.<your-domain>). - Add an
identity_providers.oidcblock to Authelia'sconfiguration.yml: anhmac_secret(another 64-char random value), the RSA key underjwks, and a client (client_id: immich, the PBKDF2 hash asclient_secret,authorization_policy: one_factor— the same level as the rest of the portal —redirect_urisfor the web app plusapp.immich:///oauth-callbackfor the mobile app,scopes: [openid, profile, email]). Restart withdocker restart nocloud_authelia(or, if you started it viadocker compose --profile auth up -d,docker compose restart authelia) and checkdocker logs nocloud_authelia --tail 20— a config error means it didn't come back up, roll back immediately. - In Immich → Administration → Settings → OAuth: issuer URL = your Authelia URL, paste the
client ID/secret, scope
openid email profile, auto-register off (link your existing account by hand once, under Account Settings → OAuth). - Verify: a private window on Immich's URL should offer "Sign in with NoCloud"; with a portal session already open, the Photos tile should go straight in, no credentials asked.
- This changes login for every service behind Authelia — apply it with the owner present.
Rollback is independent per side: re-enabling Immich's password login doesn't touch
Authelia; removing the
identity_providersblock and restarting Authelia removes the OIDC provider entirely. Server config snapshots live inbackup_server_configs.sh's backup. - Home Assistant doesn't ship OIDC out of the box — the practical equivalent is the
community
hass-oidc-authcomponent, or the more pragmatictrusted_networks(auto-login from the LAN/VPN). Decide this separately; lower priority since HA already lives behind the VPN.
- Generate the secrets on the server: a client secret
(
- Run
scripts/setup_server.shfor the read-only security sudoers grant the doctor console needs, plus the systemd timer that keeps the egress allowlist fresh. - WireGuard and the egress lockdown: Network & outbound traffic, Security & privacy.
3. Publish
Back on the workstation: nocloud deploy — builds every page and the API and pushes them to the server.
The commands you'll use most:
| Command | What it does |
|---|---|
nocloud onboard <path> |
bring in photos/videos, a WhatsApp export or a Takeout export, then build |
nocloud build |
build without deploying (into build/site) |
nocloud test |
smoke test against synthetic data |
nocloud update |
pull the latest version and its dependencies |
nocloud jobs run check_updates |
check whether a real new version has been released, without pulling (new commits alone don't count — only a VERSION bump does) — a banner appears at the top of every page once it has. Also checks a companion nocloud-store checkout the same way, if you have one |
nocloud doctor |
installation diagnostics (text or JSON) |
nocloud journey |
the next meaningful product step (text or JSON) |
nocloud jobs list |
job registry: list / status / run <id> / history |
nocloud upgrade run |
full lifecycle: preflight → backup → migrate → build → deploy → verify |
nocloud module list |
module SDK: list / doctor / install / remove / registry |
That's 10 of 24 commands — the complete list, with every flag, lives in the CLI reference.
Tip
nocloud init installs the code and data, separate from the launcher script itself.
Removing ~/nocloud never touches anything already deployed on the server.