Personal Self-Hosted

Run your own Contextify Cloud server, end to end.

Go from nothing to a running deployment two ways: hand it to your coding agent and let it do the setup, or walk the four manual steps yourself. Either way it is one server you operate: bring up the server, put HTTPS in front of it, point Contextify at it, and confirm search and recall work.

Personal Self-Hosted is the free, single-user way to run the Contextify Cloud sync server on your own hardware. It is source-available under the Functional Source License, Version 1.1, Apache 2.0 Future License (FSL-1.1-Apache-2.0). Each release converts to the Apache License 2.0 two years after it ships, and the source is on GitHub.

Fastest path

Let your AI set it up

You already drive a coding agent. Hand it this runbook and it stands the server up for you, running each command in your shell and pausing to ask you at the choices that matter. Everything runs on your machine.

Paste this to your AI

Copy this prompt into Claude Code, Codex, or any coding agent. It points the agent at a runbook we keep current, so the prompt stays short and stable.

Help me set up a self-hosted Contextify server on this machine. Read the runbook at https://contextify.sh/docs/self-hosted/agent-setup.md and follow it exactly: run the commands in my shell, show me what you are doing, generate any secrets locally on this machine, and pause to ask me at every step marked [ASK ME]. When it is done, verify the server is healthy and my Contextify app can search across it.

The runbook lives at contextify.sh/docs/self-hosted/agent-setup.md. If your agent cannot fetch a URL, open it and paste its contents into the chat.

What your AI does, and what stays in your control

  • It runs commands in your terminal and shows you each one.
  • It generates secrets on your machine and writes them only into the server's config file, not into the chat.
  • It pauses to ask you at the choices that matter: your server's URL, any change outside the project, and before it creates your account.
  • You can stop at any point.

During setup nothing is sent anywhere. Once it is running, your history syncs to the server you just created, and nowhere else.

Coming soon: if you use the contextify CLI with Claude Code or Codex, a built-in setup skill will make this a single command. It ships in a future Contextify release; until then, use the prompt above.

Do it yourself

Before you start

Prefer to run it by hand, or want to read exactly what your agent would do? These are the same four steps, start to finish.

A machine you operate

A Mac mini, a Linux box, or a private tailnet host with Docker installed. A spare machine on your network is enough; there is no Contextify infrastructure in the path.

Docker

Docker with Compose v2 (docker compose). The stack builds the API image locally and runs PostgreSQL alongside it.

The public source

The contextify-cloud-self-hosted repository holds the Docker stack you run.

Decide your server's URL first. The address your machines will use is baked into the server's configuration and its TLS certificate, so choose it before you write any config. A Tailscale HTTPS hostname (your-host.your-tailnet.ts.net) is the simplest choice: it gives you a stable name and a valid certificate without exposing anything to the public internet. You can also use a LAN hostname with your own certificate. Use this URL everywhere the steps below ask for your server URL.

Step 1: Run the server

Clone the public source and create your environment file from the example:

git clone https://github.com/PeterPym/contextify-cloud-self-hosted.git
cd contextify-cloud-self-hosted
cp .env.example .env

Set your secrets and URLs in .env

Generate three secrets at the shell and copy each value into .env. Do not paste a $(...) command into the file: Docker Compose reads .env literally and does not run commands, so a $(openssl ...) line would become your actual secret.

openssl rand -hex 32    # copy into API_SECRET_KEY
openssl rand -hex 20    # copy into DB_PASSWORD
openssl rand -hex 32    # copy into CONTEXTIFY_SELF_HOSTED_SETUP_TOKEN

Then edit .env so these values are set:

Variable What to do
API_SECRET_KEY Replace the shipped dev-secret-change-me with your generated 32-byte hex. The server refuses to start on the default value.
DB_PASSWORD Replace the default contextify with your generated 20-byte hex. Set this before the first start (see the warning below).
CONTEXTIFY_SELF_HOSTED_SETUP_TOKEN Add this line. It is not in .env.example, and the stack will not start without it. It gates the one-time owner-setup page.
ALLOWED_ORIGINS Replace the example value entirely with your server's URL. The default includes addresses you do not need.
EMAIL_BASE_URL, INVITATION_BASE_URL Change both from the localhost default to your server's URL.
SELF_HOSTED Leave it true.

Set DB_PASSWORD before the first start. PostgreSQL applies the password only when its data volume is first created. If you start the stack on the default and change DB_PASSWORD afterward, the API can no longer reach the database. Changing it later means resetting the database volume.

The DATABASE_URL line in .env.example is ignored by this Compose file, which builds its own connection string from DB_PASSWORD, so you do not need to edit it. Login is by password, so an email provider is optional: leave RESEND_API_KEY empty and auth emails are written to the server log instead of sent.

Start the stack

docker compose -f docker-compose.selfhosted.yml up -d --build

The first run builds the API image, which takes a few minutes on a small machine. Check progress with docker compose -f docker-compose.selfhosted.yml ps. The API binds to loopback (127.0.0.1:8443) by default; Step 2 puts HTTPS in front of it.

Confirm it is healthy

curl -s http://127.0.0.1:8443/api/v1/health

A healthy self-hosted server returns:

{"status": "ok", "self_hosted": true}

You create the owner account in Step 2, once your real hostname and HTTPS are in place, so the setup link points at the address your machines will actually use.

Step 2: Secure it

The API listens on a loopback port; you reach it over HTTPS at a stable hostname with a matching TLS certificate. The recommended path is Tailscale HTTPS: it puts HTTPS in front of the loopback API port at a .ts.net hostname that stays on your private tailnet, so the server is never exposed to the public internet. The hostname the certificate proves is the hostname you configure Contextify with. Exposing the server publicly with your own reverse proxy is an advanced option where you own the TLS, authentication, and rate-limiting hardening; keep it private unless you have a specific reason not to.

Read the TLS, VPN, and Tailscale guide

Match your config to the final URL

Once HTTPS is in front, confirm the server is configured for that exact origin:

  • Check the URL variables

    Confirm ALLOWED_ORIGINS, EMAIL_BASE_URL, and INVITATION_BASE_URL in .env all match your final HTTPS origin.

  • Turn on secure cookies

    Set FORCE_SECURE_COOKIES=true in .env. The example ships it as false for local HTTP validation.

  • Apply the changes

    Rerun docker compose -f docker-compose.selfhosted.yml up -d so the container picks up the updated environment.

Create the owner account

Personal Self-Hosted is single-user; this first account is the server's owner. Create it once, at your real HTTPS hostname. Either open the one-time setup page in a browser:

https://your-server.example.ts.net/setup?token=YOUR_SETUP_TOKEN

or, for a headless server, create the owner from the command line:

docker compose -f docker-compose.selfhosted.yml exec api \
  python -m contextify_cloud create-admin --email you@example.com

The setup page is available only while no owner exists. A wrong or missing token returns a 404, and once an owner is created the page returns 410 and stops working. The workspace name field on the setup form is only a label for your single-user server. Treat the setup token like a password: it appears in your URL and shell history, and it becomes inert once the owner account exists.

Step 3: Point Contextify at it

With the server running and reachable, connect your machines. Use the server URL and a sync-capable API key created from the dashboard.

Mac app

Open Settings, then Cloud, and choose Contextify Cloud Self-Hosted. Enter your server URL (the hostname on the TLS certificate) and paste a sync-capable API key.

Linux or the CLI

Run contextify cloud setup --url https://your-server.example.ts.net, then contextify cloud status --json and contextify cloud sync.

Read the full connect walkthrough

If your server is reachable only inside a VPN or tailnet, run the connect commands from a device on that network.

Step 4: Verify search and recall

Confirm the round trip works end to end from a machine you have connected.

  • Confirm sync

    Run contextify cloud status --json and check that recent projects have synced. You can also open the read-only dashboard at your server's URL.

  • Search your history

    Search from the Mac app or the dashboard for a term you know is in a past session. Results come from the server you operate.

  • Recall in your assistant

    Use Total Recall to bring a past decision, fix, or debugging session into the work happening now: /total-recall in Claude Code, $total-recall in Codex.

Just connected and search is empty? The app finishes indexing local history before it syncs, so a large first run can take time. Read about ingestion and syncing to understand what happens before Cloud catches up.

Keep going

Last updated: July 10, 2026