Critto normally lives in your Critto account. If you'd rather keep everything on a computer you own, you can run the Critto server yourself: your crittos, their memories and your chats stay on that machine, and the Critto desktop and phone apps connect to it.

This guide is for Linux. You'll need:

  • a 64-bit Linux computer (Intel/AMD or ARM, e.g. a Raspberry Pi 4/5) that stays on: a home server, a mini PC, or a small cloud server,
  • about 1 GB of free memory and a few GB of disk,
  • administrator rights (sudo).

NixOS gets a flake with a NixOS module. Debian, Ubuntu, Fedora, RHEL-style systems and openSUSE get proper packages with automatic updates. Anything else can use the container image or the static build.


NixOS

Add Critto's flake to your system flake:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    critto.url = "https://downloads.critto.app/nix/critto.tar.gz";
    critto.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = { nixpkgs, critto, ... }: {
    nixosConfigurations.myserver = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";            # or aarch64-linux
      modules = [
        ./configuration.nix
        critto.nixosModules.default
        ({ pkgs, ... }: {
          services.critto = {
            enable = true;
            # Secrets (Boat key, backup key) stay out of the Nix store:
            environmentFile = "/etc/critto/secrets.env";
            # AI apps for your subscriptions (you sign in from the app):
            aiPackages = [ pkgs.codex pkgs.nodejs_22 ];
            # publicUrl = "https://critto.example.com";
          };
        })
      ];
    };
  };
}

Then sudo nixos-rebuild switch --flake .#myserver and pair your apps with sudo crittod pair (step 2).

  • Updates: nix flake update critto, then rebuild. The package is the signed, prebuilt release (a static binary, so no glibc trouble). Use services.critto.package = critto.packages.${system}.crittod-beta; for the beta channel.
  • Secrets: put BOAT_API_KEY=… and CRITTO_BACKUP_KEY=… in the environmentFile (root-owned, mode 600; agenix and sops-nix work too). It's read when the service starts and never copied into the store.
  • Settings: listen (default 127.0.0.1:8787), publicUrl, webHost, openFirewall (default off), dataDir (default /var/lib/critto) and settings for any other CRITTO_* variable. den.backend picks where the Den runs (boat, local or none; see the Den).
  • AI apps: prefer packages from nixpkgs in aiPackages (for example pkgs.codex, pkgs.claude-code, which needs allowUnfree). For the ones nixpkgs doesn't have, set programs.nix-ld.enable = true; and use sudo crittod setup ai (step 3). Pi only needs pkgs.nodejs_22 in aiPackages, then sudo crittod setup ai pi.
  • Remote access: services.tailscale.enable = true; then sudo tailscale serve --bg 8787, or services.cloudflared with an ingress rule to http://127.0.0.1:8787 (see step 5).
  • The service is sandboxed with systemd but keeps user namespaces available (bubblewrap and the local Den need them), so don't set security.allowUserNamespaces = false.

The rest of this guide applies to NixOS too, except that updates come from nix flake update instead of apt or dnf.


1. Install

Open a terminal on the server and run:

curl -fsSL https://downloads.critto.app/install-server.sh | sh

It adds Critto's package repository, installs the critto-server package, starts the server and prints a pairing code. That's it: skip to Pair your apps.

Want new versions before everyone else? Use the beta channel: curl -fsSL https://downloads.critto.app/install-server.sh | CRITTO_CHANNEL=beta sh

Check the installer first (optional)

The script is signed with Critto's release key. To verify it before running:

curl -fsSLO https://downloads.critto.app/install-server.sh
curl -fsSLO https://downloads.critto.app/install-server.sh.minisig
minisign -Vm install-server.sh -P RWTRac/2j5M3cvVpvtz0flaOy7sH5PFSc4LwbB7PxG0OMO2h8APoZtLG
sh install-server.sh

(minisign is in most distributions' packages.) There's also a plain checksum at install-server.sh.sha256. The packages themselves are signed too, and your package manager checks them on every install and update.

Or set up the repository yourself

Debian / Ubuntu:

sudo install -d -m 755 /etc/apt/keyrings
sudo curl -fsSLo /etc/apt/keyrings/critto.gpg https://downloads.critto.app/keys/critto-archive-keyring.gpg
cat <<EOF | sudo tee /etc/apt/sources.list.d/critto.sources
Types: deb
URIs: https://downloads.critto.app/apt
Suites: stable
Components: main
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/critto.gpg
EOF
sudo apt update && sudo apt install critto-server

Fedora / RHEL / Rocky / Alma:

sudo rpm --import https://downloads.critto.app/keys/critto-archive-keyring.asc
cat <<EOF | sudo tee /etc/yum.repos.d/critto.repo
[critto]
name=Critto
baseurl=https://downloads.critto.app/rpm/stable
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://downloads.critto.app/keys/critto-archive-keyring.asc
EOF
sudo dnf install critto-server

The key's fingerprint is C78E FB7F 67CC 8184 1F70 EE3D D121 DC94 C534 50E3 ("Critto Packages packages@critto.app").

Or use Docker / Podman

docker run -d --name critto --restart unless-stopped \
  -p 127.0.0.1:8787:8787 \
  -v critto-data:/var/lib/critto -v critto-keys:/etc/critto -v critto-ai:/opt/critto-ai \
  ghcr.io/nexferra-ltd/critto-server:latest
docker exec critto crittod pair

The container needs no special permissions. Your data lives in the critto-data volume, the vault's master key in critto-keys (kept apart from the data, so a copy of one never opens the other; see Backups), and the AI apps in critto-ai. A Docker secret mounted at /etc/critto/vault.key works too. Update with docker pull ghcr.io/nexferra-ltd/critto-server:latest, then recreate the container with the same volumes.

Or the static build

Every release also has a single-file build that runs on any Linux: https://downloads.critto.app/releases/<version>/critto-server-<version>-linux-x86_64.tar.gz (or -aarch64). Unpack it and run ./crittod serve. You'll have to keep it running and up to date yourself, so the packages are the easier choice.


2. Pair your apps

The server only lets in devices you've paired. To pair one:

  1. On the server, get a code (it's valid for 10 minutes and works once):

    sudo crittod pair
    
  2. In the Critto app, on the sign-in screen, choose Use my own Critto server. Enter the server's address and the code.

Once one device is paired, you can pair more from it: Settings → Devices → Pair a phone shows a QR code. It carries the address the server listens on; if your devices reach it some other way (a tunnel, a proxy, a domain), set CRITTO_PUBLIC_URL to that address (see Settings).

Desktop app on the same computer? The desktop app normally starts a private Critto server of its own. If you've installed the server here, choose Use my own Critto server with http://127.0.0.1:8787 instead, so both use the same crittos.


3. Connect your AIs

Crittos think with an AI you choose. There are two ways to bring one.

Your AI subscriptions (ChatGPT, Claude, Grok…)

Critto talks to these through their official command-line apps, which you install on the server once:

sudo crittod setup ai

Pick the ones you use, or name them directly: sudo crittod setup ai codex claude.

App Use it with
codex a ChatGPT plan (Plus, Pro, Business…)
claude a Claude plan (Pro, Max…)
grok SuperGrok / X Premium
muse Meta AI (needs Node.js 20+; the installer adds it if it can)
antigravity Google Antigravity. Read the warning it shows first: Google's terms say other software shouldn't use an Antigravity sign-in, and Google has suspended accounts for it.

They're installed in /opt/critto-ai and don't update themselves. Run sudo crittod setup ai --update now and then to update them.

Then, in the Critto app, open Connections and sign in to each one. The sign-ins are stored on your server, not in the app.

Custom AI: local models and API keys

Turn on Settings → Advanced mode, then use Settings → Custom AI → Add connection. Anything that speaks the "OpenAI-compatible" API works. Pick a preset under Start from, or fill in the address yourself:

Service Base URL API key
Ollama on the server http://localhost:11434/v1 none
LM Studio on the server http://localhost:1234/v1 none
Ollama on another computer at home http://192.168.1.20:11434/v1 none
OpenRouter https://openrouter.ai/api/v1 your OpenRouter key

Use Test connection, pick a model and save. You can then choose that AI for any critto.

For Ollama on another computer, start it with OLLAMA_HOST=0.0.0.0 so it accepts connections from your network. "localhost" always means the Critto server's own machine.


4. The Den (optional)

The Den is your crittos' own computer in the cloud, where they do bigger jobs (build things, browse, use apps). A self-hosted server runs Dens on your own Boat account. Paste your Boat API key in the app under Connections, or put it in the settings file as BOAT_API_KEY and restart.

Good to know:

  • Your server doesn't need to be reachable from the internet for the Den to work. It talks to the Den, not the other way around.
  • Den work needs an AI with a public internet address (your subscriptions or a service like OpenRouter). An AI running on your own network (Ollama, LM Studio) can chat, but the Den in the cloud can't reach it.
  • Den time is billed by Boat on your account.

Your own Den, on your own machine

No Boat account? The server can run each person's Den as a small virtual machine on this computer instead (it needs /dev/kvm, about 4 GB of memory per Den while it runs, and a one-time image build). On NixOS:

services.critto.den.backend = "local";

Elsewhere, CRITTO_DEN_BACKEND=local in /etc/critto/critto.env. The full guide (requirements, sizes, what a Den can reach, building the image) is in Your own Den, on your own machine.


5. Reach it from your other devices

Out of the box the server only listens on its own computer (127.0.0.1:8787). That's the safe default. To use your phone or laptop from anywhere, pick one of these. The first two give you a secure https:// address without opening ports on your router.

Tailscale (easiest for personal use)

Install Tailscale on the server and on your devices, sign in to the same account, then on the server:

sudo tailscale serve --bg 8787

It prints an address like https://myserver.tail1234.ts.net. Use that in the apps. Only your own devices can reach it.

Cloudflare Tunnel (a public address on your own domain)

With a domain on Cloudflare, install cloudflared, then:

cloudflared tunnel login
cloudflared tunnel create critto
cloudflared tunnel route dns critto critto.example.com
cat > ~/.cloudflared/config.yml <<EOF
tunnel: critto
credentials-file: $HOME/.cloudflared/$(cloudflared tunnel list | awk '/critto/{print $1}').json
ingress:
  - hostname: critto.example.com
    service: http://127.0.0.1:8787
  - service: http_status:404
EOF
sudo cloudflared service install

Your server is then at https://critto.example.com. Every device still needs a pairing code.

A reverse proxy you already run

Point it at http://127.0.0.1:8787 with WebSockets allowed. With Caddy, which handles HTTPS by itself:

critto.example.com {
    reverse_proxy 127.0.0.1:8787
}

On your home network only

If every device is at home, you can let the server listen on your network directly. Set CRITTO_LISTEN=0.0.0.0:8787 (see Settings) and use http://<server's IP address>:8787 in the apps. This is plain http, so only do it on a network you trust.

Whichever you choose, set CRITTO_PUBLIC_URL to that address so pairing QR codes point at it.


6. Updates

The server updates with the rest of your system:

  • Debian / Ubuntu: sudo apt update && sudo apt upgrade
  • Fedora / RHEL: sudo dnf upgrade
  • openSUSE: sudo zypper update

The service restarts by itself after an update. The desktop and phone apps update separately.


7. Backups

Everything lives in /var/lib/critto: your crittos, memories, chats, files and AI sign-ins. Settings are in /etc/critto/critto.env.

Copy it yourself. Stop the server for a consistent copy:

sudo systemctl stop critto
sudo tar czf critto-backup-$(date +%F).tar.gz --exclude=/etc/critto/vault.key /var/lib/critto /etc/critto
sudo systemctl start critto

The server also keeps a fresh copy of its database at /var/lib/critto/backups/latest.db while it runs.

Off-site backups (S3, Cloudflare R2, Backblaze B2…). In the app, turn on Advanced mode, then use Settings → Backups → Change target…. Encrypt them before they leave your server by adding a backup key:

sudo crittod backup keygen

Copy the CRITTO_BACKUP_KEY=… line into /etc/critto/critto.env, keep a copy somewhere safe and offline (backups can't be restored without it), and restart: sudo systemctl restart critto.

Off-site backups are continuous:

  • the database's changes go up every 10 seconds;
  • people's files go up every 10 minutes;
  • a full copy goes up every day.

Any moment of the last 7 days can be restored straight from the bucket:

sudo systemctl stop critto
sudo -u critto crittod backup list
sudo -u critto crittod backup pitr --to /var/lib/critto/restore --at "2026-10-02 14:30"
sudo -u critto mv /var/lib/critto/restore/critto.db /var/lib/critto/critto.db
sudo systemctl start critto

(--at is UTC; leave it out for the latest state. The restored users/ folder is in the same place.)

To restore a single downloaded backup file instead (a daily snapshot), put it somewhere the critto user can read (e.g. /var/lib/critto), then:

sudo systemctl stop critto
sudo crittod backup restore --from /path/to/downloaded-backup --to /var/lib/critto/restored.db
sudo -u critto mv /var/lib/critto/restored.db /var/lib/critto/critto.db
sudo systemctl start critto

The vault's keys. Saved keys and passwords are encrypted with a master key in /etc/critto/vault.key (created at install, readable only by the critto user; in Docker the critto-keys volume, on NixOS services.critto.vaultKeyFile, by default /var/lib/critto-keys/vault.key: always outside the data). It is never in a backup. The list of per-account keys it unlocks (/var/lib/critto/vault/keys.db) gets its own encrypted backup next to the others, under vault/, kept 30 days, but only if you give it a recovery key:

sudo crittod vault recovery-keygen

Put the CRITTO_VAULT_BACKUP_RECIPIENT=… line in /etc/critto/critto.env and restart. Keep the printed recovery identity and a copy of /etc/critto/vault.key offline, in your password manager: never on the server. To restore after losing the server, put vault.key back, download vault/latest.db.age, then:

sudo -u critto crittod vault restore --identity /path/to/recovery.txt /path/to/latest.db.age

Settings

The server reads /etc/critto/critto.env. Every option is listed there with an explanation. Edit it with sudo nano /etc/critto/critto.env, then sudo systemctl restart critto. The common ones:

Setting What it does
CRITTO_LISTEN Where the server listens. Default 127.0.0.1:8787 (this computer only).
CRITTO_PUBLIC_URL The address your devices use, e.g. https://critto.example.com.
BOAT_API_KEY Your Boat key, for the Den.
CRITTO_BACKUP_KEY Encrypts off-site backups.
CRITTO_ANTIGRAVITY=0 Hides Antigravity.
CRITTO_PROACTIVE=0 Crittos don't check in by themselves (things they scheduled wait). Without Critto AI, check-ins think with the critto's own AI.
CRITTO_JOB_WORKERS How many background jobs (check-ins, scheduled things) run at once. Default 4.

Useful commands:

Command
sudo crittod pair a pairing code for a new device
sudo crittod setup ai install or update AI apps
sudo crittod users the accounts on this server
systemctl status critto is it running?
journalctl -u critto -f its log
curl http://127.0.0.1:8787/health a quick health check

/health says "desktop": "on-demand" until a Den first needs its desktop software. That's normal: the server downloads it then.


Uninstall

  • Debian / Ubuntu: sudo apt purge critto-server
  • Fedora / RHEL: sudo dnf remove critto-server
  • Docker: docker rm -f critto (add docker volume rm critto-data critto-keys critto-ai to delete the data too)

This stops the server and removes the package and, if no other Critto package is left, the repository. Your data in /var/lib/critto is kept in case you come back. To delete everything:

sudo rm -rf /var/lib/critto /etc/critto /opt/critto-ai
sudo userdel critto

To keep the packages from adding the repository in the first place, run echo CRITTO_REPO=no | sudo tee /etc/default/critto before installing.


Troubleshooting

  • The app says it can't reach the server. Check systemctl status critto on the server, and that the address in the app is one the device can reach (from a phone, 127.0.0.1 means the phone itself).
  • "The pairing code didn't work." Codes last 10 minutes and work once. Make a new one with sudo crittod pair. Run it with sudo: without it you get a code for a different, personal server.
  • An AI app doesn't show up in Connections. Run sudo crittod setup ai <name> again; it restarts the server when it's done.
  • Something else. journalctl -u critto -n 100 usually says what's wrong.