Self-host Charyl on your own Linux server

Docker Engine and Compose on a Linux box you already own — the same runtime the appliance runs, on hardware that's yours.

shipped Setting up Verified Aug 21, 2026 10 min read

Run the full Charyl stack on a Linux server you keep on — the same Docker runtime the appliance runs, just on hardware that’s yours. This is the self-host path: free, real today, and pulling the same published images the appliance ships with.

What you need

  • A Linux box you keep on — a home server, a mini-PC, or a VM. amd64/x86-64 today; arm64 images are still a work in progress.
  • Docker Engine and Compose v2 (docker compose version reports v2 or later) — Engine on Linux, not Docker Desktop.
  • A local model runtime for AI and embeddings (Step 3 below). Without it, semantic search stays dark; everything else still works.
  • A couple of GB of RAM headroom, and disk space for the database and uploads.

The stack binds four ports on the host: 8080 (the web app), 5142 (the API and realtime hub), 1883 (MQTT, for sensor nodes), and 8123 only if you turn on the bundled Home Assistant. The database, Charyl, and the updater are never exposed to your network — by design.

  1. Get the files

    During the testing period we send you the compose bundle — docker-compose.yml, .env.example, and the helper scripts — together with registry access when your early-access request is approved. Unpack it into the directory you’ll run from, then:

    cp .env.example .env

    You don't need the source to run the stack

    It pulls prebuilt images — the bundle is just the compose file and its helper scripts. At release, both the bundle and the images are public.

  2. Configure .env

    Open .env and set the handful of knobs that matter for a self-host box. Most already have working defaults:

    VariableSet it toWhy
    SINGER_VERSION / CHARYL_VERSIONthe release you’re runningPins the image versions — the two numbers drift apart on purpose.
    SINGER_PROJECT_DIRthe absolute path of this directory (e.g. /opt/singer)Required for the auto-updater to apply releases correctly.
    GHCR_USERNAME / GHCR_READ_TOKENyour GitHub username and a read:packages tokenOnly during the private-testing period — Step 4 below. Goes away once images are public.
    SIH_ANTHROPIC_KEYyour AI provider key (optional)Enables Charyl’s chat and product research. Not needed just to onboard.
    TAVILY_API_KEYa web-search provider key (optional)Used only if web search is enabled.
    TZyour timezoneMaintenance-window and log timestamps.

    Leave SINGER_REGISTRY unset — the default is correct. Do not put a database password or signing key in .env; the stack generates those itself, per box, the first time it boots.

    Leave ADMIN_PASSWORD blank and the app generates a random one, printed once in the log — you’ll grab it in Step 6. Set ADMIN_EMAIL to the address you want to log in with.

  3. Install a local model runtime

    The stack expects a local model runtime reachable at http://host.docker.internal:11434. Install it on the host, then pull the models Charyl uses:

    curl -fsSL https://ollama.com/install.sh | sh     # host-native install
    ollama pull <chat-model>                           # value of OLLAMA_MODEL in .env
    ollama pull <embedding-model>                       # the model Charyl embeds with

    Check the exact model names against your release — the chat model must be tool-capable. Semantic search stays dark until the embedding model is present; everything else runs without it.

  4. Log in to the image registry

    While the images are private, authenticate Docker with a GitHub token scoped to read:packages — nothing more:

    docker login ghcr.io -u "$GHCR_USERNAME" --password-stdin <<< "$GHCR_READ_TOKEN"

    Testing period only

    Once the images are published publicly, this step is unnecessary — a plain docker compose up pulls anonymously.

  5. Bring it up

    docker compose up -d          # pulls published images; NO --build
    docker compose ps             # watch until services are healthy

    On first boot, a one-shot container mints this box’s own database password, signing key, API key, and updater secret into a private volume — nothing hardcoded, nothing in .env, different on every box.

    Two volumes share one fate

    The secrets and postgres_data volumes are a matched pair. docker compose down -v wipes both together — safe, and how you get a clean box. Wiping only one of them causes a password mismatch.

  6. Onboard

    docker compose logs singer-hkg-api | grep -i "GENERATED SEED ADMIN PASSWORD"

    Open http://localhost:8080 (or http://<box-lan-ip>:8080 from another device on your network), log in with ADMIN_EMAIL and that generated password, and follow the first-run wizard — including, if you want it, connecting to Charyl Cloud.

    That’s it — the stack is running, and, if you pair it to Charyl Cloud, keeps itself updated.

Updates and day-to-day

  • Updates. With a Charyl Cloud subscription the updater applies releases automatically in a maintenance window — pull by digest, recreate, health-gate, roll back if unhealthy. Without one, update by hand: docker compose pull && docker compose up -d. Either way SINGER_PROJECT_DIR must be set for the updater.
  • Logs. docker compose logs -f <service> — for example singer-hkg-api or singer-charyl.
  • Stop and start. docker compose stop and docker compose up -d. Your data lives in named volumes and survives restarts and updates.
  • Optional Home Assistant. Add COMPOSE_PROFILES=homeassistant to .env to run the bundled, version-pinned Home Assistant on port 8123 — see Connect Home Assistant. Households running their own leave this unset.

Troubleshooting

SymptomCause and fix
A service won’t pullRegistry auth (Step 4) — confirm docker login ghcr.io succeeded and your token has read:packages. Unneeded after public release.
Postgres never goes healthy after resetting only one volumeThe secrets/postgres_data shared-fate rule (Step 5) — run docker compose down -v to come back up clean.
Semantic search returns nothingConfirm the local model runtime is running on the host and the embedding model is pulled; check docker compose logs singer-charyl for the embed call.
Can’t log in, or lost the admin passwordSet ADMIN_PASSWORD and ADMIN_RESET_PASSWORD=true in .env for one boot, then unset it.

Next

Once the stack is up, the first-run wizard covers naming your home, connecting Home Assistant, and pairing a phone.