Standing up and maintaining a box (operator)
For whoever runs the box. This is the most technical of the docs.
The appliance model
Section titled “The appliance model”A Lowkey box is one self-contained deployment for one person or one trusted group: its own server, data, projects, provider logins, and agents. The person who runs that server is the operator.
The provisioner is for a fresh Ubuntu VPS. It gets the machine ready to run
Lowkey in the product shape: an operator user, app files under /opt/lowkey,
nginx in front, TLS for your domain, and system-level hardening around SSH,
firewalling, memory pressure, and provider tooling.
Run the provisioner
Section titled “Run the provisioner”Point the domain’s DNS at the VPS first, then run the provisioner from a Lowkey checkout:
./provision/provision.py joy-lowkey 203.0.113.10 --user joy --domain joy.example.comThe first argument becomes the system hostname. The IP address is where the
script connects as root. --user is the operator account it creates and uses
for normal Lowkey work. --domain tells it to render the product nginx template
and request a Let’s Encrypt certificate with certbot.
You can omit --domain if DNS is not ready yet. In that case nginx is installed,
but the Lowkey site and TLS certificate are left for later.
The script is designed to be re-run. It creates or updates the same pieces each
time: packages, Docker, Node, Python, Go, provider CLIs, the lowkey CLI shim,
the operator user, /opt/lowkey, swap, systemd daemon drop-ins, SSH hardening,
UFW, fail2ban, nginx, and, when a domain is provided, the nginx site and TLS
certificate. Re-running is normal when a previous pass stopped halfway, but
remember that it reapplies the intended firewall and nginx choices.
What is ready afterward
Section titled “What is ready afterward”After provisioning, the box has the operating-system side ready. The app
checkout is expected to live in /opt/lowkey, owned by the operator user. Keep
that path outside any workspace root; otherwise Lowkey can discover its own
application checkout as a project.
The daemon is expected to run as lowkey-daemon.service, with memory and
per-session containment drop-ins already staged under
/etc/systemd/system/lowkey-daemon.service.d/. The web app runs separately as
the web service in Docker Compose. The nginx template sends API and websocket
traffic to the daemon on 127.0.0.1:7070, sends the web UI to
127.0.0.1:3000, redirects HTTP to HTTPS, and uses the daemon’s /api/auth
endpoint for cookie auth.
Provisioning does not yet finish the whole box by itself. The remaining manual
work is to put the Lowkey code into /opt/lowkey, deploy it there, generate
~/.lowkey/config.json with a fresh password and API key, choose workspace roots
that do not include /opt/lowkey, then connect providers in Settings ->
Providers.
Staying in control
Section titled “Staying in control”Treat a box as a trust boundary. Anyone with access to it can ask agents to act with that box’s files, provider sessions, and local credentials. Add people only when you would trust them with the whole machine.
Provisioning also changes real infrastructure: SSH policy, firewall rules, nginx, TLS, and systemd configuration. Re-run it deliberately, and schedule app deploys or daemon restarts for a time when interrupting active work is okay.
What to read next
Section titled “What to read next”- Connecting providers ->
/operator/providers/ - Defining agents ->
/operator/agents-config/ - Sharing a box with people ->
../multi-user.md