Install a server
A Kedalio server is three containers: the server, Caddy in front of it for HTTPS, and a first host next to them. You install them with one command, or as a resource on a Coolify server you already run.
What you need
Section titled “What you need”- A Linux machine with Docker and Docker Compose v2 (
docker compose). The installer stops and says so when either is missing. - A domain whose DNS points at the machine, for example
app.example.com. Caddy gets its certificate from Let’s Encrypt. - Ports 80 and 443 (TCP, and UDP for 443) free on the machine. Caddy is the only container that listens outside.
sudo, once, on a machine that enforces AppArmor: the host’s profile is loaded into the kernel.
The host image is built for amd64 and arm64.
With the installer
Section titled “With the installer”curl -fsSL https://get.kedalio.com | shIt asks one question:
Domain for Kedalio (its DNS must point at this machine), e.g. app.example.com:Then it:
- pulls the server and host images;
- writes the installation’s folder,
~/kedalio:compose.yaml,Caddyfile, the host’s seccomp and AppArmor profiles, all taken from the host image of the same version, and.envwith the domain and a one-use join code for the first host; - loads the host’s AppArmor profile into
/etc/apparmor.d, on a machine that has AppArmor (this is thesudo); - starts the three containers;
- prints the link that makes your account.
Kedalio is up. Make your account (the link works once, for seven days):https://app.example.com/invite#…Open it, choose how you sign in (a passkey, a password with the code of an authenticator app, or both), and you are the server’s first account and its administrator. The host started next to the server joins by itself once that account exists. The next steps are in Accounts and access.
Without a terminal
Section titled “Without a terminal”In a CI or a script everything comes from the environment: KEDALIO_DOMAIN, and optionally KEDALIO_DIR (the folder, ~/kedalio by default), KEDALIO_VERSION, KEDALIO_REGISTRY, KEDALIO_SERVER_IMAGE, KEDALIO_HOST_IMAGE, KEDALIO_HTTP_PORT, KEDALIO_HTTPS_PORT, KEDALIO_ENGINES (overrides the engine versions hosts install, set in the server by default; for example [email protected],[email protected]) and KEDALIO_NO_PULL=1 for images already on the machine.
Updating
Section titled “Updating”Run the installer again. It keeps .env (the domain, the join code, the version and the registry), takes the files of the new image and restarts the containers. To move to another version, give KEDALIO_VERSION; without it the installed one stays. Hosts then follow the server’s version by themselves (Add a host).
If the link does not appear
Section titled “If the link does not appear”The installer waits two minutes for the server’s first start. A server that already has its account prints no link:
Kedalio is up at https://app.example.com (no first-account link: the instance already has its account).While no account exists, the server makes a new link at every start, and the older ones stop working. It is in the server’s log:
docker compose --project-directory ~/kedalio logs server | grep "first account"On Coolify
Section titled “On Coolify”deploy/coolify/compose.yaml runs the server and one host on a Coolify server, from Kedalio’s images (the same deploy/get.sh uses), not built again by Coolify. Coolify’s own proxy is in front, so there is no Caddy.
-
Once per machine, as root, before the first deploy, load the host’s AppArmor profile from a clone of the repository:
Terminal window sudo install -m 0644 apps/host/image/apparmor/kedalio-host /etc/apparmor.d/kedalio-hostsudo apparmor_parser -r -W /etc/apparmor.d/kedalio-host -
Add a resource from the repository with the build pack Docker Compose, base directory
/, compose filedeploy/coolify/compose.yaml. -
Give the
serverservice its domain (https://app.example.com) and setKEDALIO_URLto the same address,KEDALIO_SERVER_IMAGEandKEDALIO_HOST_IMAGEto the two images (registry.example.com/kedalio/kedalio-server:<version>and…/kedalio-host:<version>). With a moving tag such as:dev, every deploy pulls the newest. -
Deploy. Coolify generates the first host’s join code once and keeps it. The first account’s link is in the
serverservice’s log, as above.
Optional variables: KEDALIO_HOST_NAME (the host’s name, local by default), KEDALIO_HOST_MEMORY (8g by default) and KEDALIO_HOST_CPUS (4), KEDALIO_ENGINES, and KEDALIO_CLIENT_IP_HEADER, the header that carries the visitor’s address. It is unset by default, and then every visitor counts as Coolify’s proxy, so set it: x-forwarded-for behind Coolify’s proxy alone, cf-connecting-ip behind Cloudflare when only Cloudflare can reach the machine (otherwise anyone can write that header).
Your data
Section titled “Your data”Everything is in the server’s volume (/data inside the container):
instance.db, and one database per account inaccounts/<id>/account.db;kek, the instance’s key, which encrypts the vault;backups/, a copy of each database taken before every migration (the newest five are kept) and one a day (the newest seven are kept). Migrations run by themselves at start.
Backing up the volume is yours or your platform’s: Kedalio has no backup command. Keep the kek file apart from a backup of the databases. If it is lost, the vault stays locked until you give the recovery code shown at your first sign-in.
Checking it
Section titled “Checking it”https://app.example.com/healthanswers the server’s name and version.https://app.example.com/readysays whether the databases and the vault are ready.
Search in the memory works by words and by meaning. Both the installer and the Coolify file start an embed service next to the server: llama.cpp with the bge-m3 model (about 600 MB, downloaded at its first start, about 800 MB of memory), on three cores with a low CPU weight so the server and the runs come first. KEDALIO_EMBED_THREADS changes the cores. Until it answers, search is by words, and says so.
Not built yet: a kedalio update command, a Railway template, and an uninstall command.