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). Useservices.critto.package = critto.packages.${system}.crittod-beta;for the beta channel. - Secrets: put
BOAT_API_KEY=…andCRITTO_BACKUP_KEY=…in theenvironmentFile(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(default127.0.0.1:8787),publicUrl,webHost,openFirewall(default off),dataDir(default/var/lib/critto) andsettingsfor any otherCRITTO_*variable.den.backendpicks where the Den runs (boat,localornone; see the Den). - AI apps: prefer packages from nixpkgs in
aiPackages(for examplepkgs.codex,pkgs.claude-code, which needsallowUnfree). For the ones nixpkgs doesn't have, setprograms.nix-ld.enable = true;and usesudo crittod setup ai(step 3). Pi only needspkgs.nodejs_22inaiPackages, thensudo crittod setup ai pi. - Remote access:
services.tailscale.enable = true;thensudo tailscale serve --bg 8787, orservices.cloudflaredwith an ingress rule tohttp://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:
On the server, get a code (it's valid for 10 minutes and works once):
sudo crittod pairIn the Critto app, on the sign-in screen, choose Use my own Critto server. Enter the server's address and the code.
- On the server itself:
http://127.0.0.1:8787 - From other devices you'll need an address they can reach; see Reach it from your other devices.
- On the server itself:
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:8787instead, 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(adddocker volume rm critto-data critto-keys critto-aito 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 crittoon the server, and that the address in the app is one the device can reach (from a phone,127.0.0.1means 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 withsudo: 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 100usually says what's wrong.