# Deployment Installs LLeMbas as a **system** service behind nginx with a self-signed certificate. Written for a systemd + nginx host; tested on Arch. | | Default | |---|---| | Service user | `lembas` (system account, `nologin`) | | Home | `/home/lembas` | | Install prefix | `/srv/lembas` (bind mount of the home) | | Checkout | `$PREFIX/app` | | Virtualenv | `$PREFIX/venv` | | Database | `$PREFIX/data/lembas.db` | | Environment | `$PREFIX/lembas.env` (mode 600) | | Unit | `/etc/systemd/system/lembas.service` | | Vhost | `/etc/nginx/conf.d/.conf` | | Listens on | `127.0.0.1:8080` — reachable only through nginx | The prefix defaults to a bind mount of the service user's home because on many machines the root filesystem is small while `/home` is not, and the virtualenv plus database belong on the larger volume. Set `PREFIX=$HOME_DIR` to skip it. ## First install ```bash SITE_HOST=chat.example ./deploy/install.sh ``` Idempotent — safe to re-run. It creates the user and bind mount, clones the repo, builds the venv, generates `lembas.env` with a fresh `LEMBAS_SECRET_KEY`, installs the unit and vhost, issues a self-signed certificate, adds a `/etc/hosts` entry if the name does not already resolve, and enables the service. Then open `https://`, accept the certificate warning, and create the first account — it becomes the administrator. Everything is overridable from the environment: | Variable | Default | | |---|---|---| | `SITE_HOST` | `lembas.local` | nginx `server_name` and certificate CN | | `APP_PORT` | `8080` | loopback port the service binds | | `SERVICE_USER` | `lembas` | system account to run as | | `HOME_DIR` | `/home/lembas` | that account's home | | `PREFIX` | `/srv/lembas` | install root (bind mount of `HOME_DIR`) | | `REPO_URL` | this checkout's `origin` | so a fork deploys itself | | `LEMBAS_BRANCH` | `main` | branch to deploy | ## Deploying a change ```bash git push ./deploy/update.sh ``` `update.sh` fetches, hard-resets the deployment checkout to `origin/main`, reinstalls dependencies and restarts, printing the commits it pulled. The hard reset is deliberate: nothing is ever edited in place there, so there is no local work to preserve and no conflicts to resolve. ## Operating it ```bash systemctl status lembas journalctl -u lembas -f sudo -u lembas /srv/lembas/venv/bin/lembas info # paths and counts ``` Configuration lives in `$PREFIX/lembas.env`. Edit it and restart. ## Notes **The secret key is generated once.** `install.sh` will not overwrite an existing `lembas.env`. Rotating `LEMBAS_SECRET_KEY` signs every user out *and* makes stored upstream API keys unreadable — they would have to be re-entered. **nginx buffering is off for a reason.** Replies stream as server-sent events. With `proxy_buffering on` (the default) nginx holds the entire reply and delivers it in one lump at the end, which is indistinguishable from streaming being broken. `proxy_read_timeout` is raised to an hour because a model can think for minutes before the first token. **Nothing an agent does runs on this machine.** Agent chats execute their commands over SSH, on a host somebody added and prepared — a container, a VM, another machine. That is the whole isolation story, and it is why the unit can stay locked down instead of being opened up to make room for a sandbox. `ProtectSystem=full` rather than `strict` only because the data directory must be writable and `strict` would mean listing every path. The practical consequence for whoever runs this: **the security of an agent chat is the security of the host behind its SSH profile.** A throwaway container with the one project mounted into it is a very different thing from a key to a production server, and LLeMbas cannot tell them apart. **Use a real certificate if this is exposed beyond a trusted LAN.** The self-signed cert exists so the install works with no external dependencies; point `ssl_certificate` at a real one and nothing else needs to change.