Before you start
You need one machine for the server. A physical box, a virtual machine on your workstation, a Proxmox or KVM guest, or a cloud instance all work. The server is headless: you will use it over SSH.
| Minimum | Recommended | |
|---|---|---|
| Architecture | x86-64 (amd64) | |
| CPU | 2 cores | 4 cores or more |
| Memory | 2 GB | 8 GB, plus the memory of any local model you run |
| Disk | 25 GB | 60 GB or more, SSD |
| Firmware | BIOS or UEFI, Secure Boot on or off | |
| Network | needed during install and first boot | |
| GPU | none | an NVIDIA RTX card if you want local models to be fast |
What you end up with. One host that has provisioned itself on its first boot:
1Choose how to install
There are three ways to get a MaluOS server. Pick one and follow its step below, then continue at step 4.
- The installer ISO (step 3). For a physical machine or a VM where you attach an ISO and boot from it. This is the usual way.
- The cloud image (step 3b). A qcow2 disk with cloud-init, for KVM, Proxmox, OpenStack and similar hosts that give a VM user data. Fastest if you already run such a host.
- An existing Ubuntu 26.04 system (step 3c). One command adds the signed MaluOS repository and the server packages; provisioning runs on the next boot.
2Download and verify the image
Every release is dated. The current one is 26.04.20261028; the number at download.maluos.com/LATEST is always the newest. Take the server file for the method you chose:
- maluos-26.04.20261028-server-amd64.iso (4.9 GB) for the installer
- maluos-26.04.20261028-server-amd64.qcow2 (1.7 GB) for the cloud image
Then check that what you downloaded is what was released. The checksum file is signed with the MaluOS Archive Signing Key (2026), fingerprint 6387 5A4A 5397 B902 E9C5 CFF8 731A DA39 4135 B9FF. In the folder with the download:
V=26.04.20261028
curl -fsSLO https://download.maluos.com/$V/SHA256SUMS
curl -fsSLO https://download.maluos.com/$V/SHA256SUMS.gpg
curl -fsSL https://apt.maluos.com/bootstrap/maluos-archive-keyring.gpg -o maluos-archive-keyring.gpg
gpg --no-default-keyring --keyring ./maluos-archive-keyring.gpg --verify SHA256SUMS.gpg
sha256sum -c SHA256SUMS --ignore-missing
What you should see: gpg prints Good signature from "MaluOS Archive Signing Key (2026) <[email protected]>" with the fingerprint above, and sha256sum prints OK next to your file. Stop if either differs.
3Install from the ISO
- Write the ISO to a USB stick with
dd, Rufus or balenaEtcher, or attach it to the VM as its CD drive. Boot the machine from it. Secure Boot can stay on. - Choose an entry in the boot menu:
- Install MaluOS Server walks you through language, keyboard, network, proxy, disk layout, your user account and SSH access. Give the machine a hostname you will recognise and add your SSH public key when asked.
- Install MaluOS Server (automated, erases first disk) is hands-off. It wipes the first disk without asking, creates the user
maluoswith the passwordmaluos, and forces a password change at the first login. Use it for throw-away VMs, not on a machine with data you want.
- Wait for the install. The MaluOS root filesystem and packages come from the medium; keep the machine on the network, since the installer fetches package updates from the Ubuntu archive. The machine reboots when it is done; remove the medium if it boots back into the installer.
The screens say Ubuntu. The shipped ISO uses the Ubuntu live installer, so its screens show Ubuntu naming during the install. What it installs is MaluOS, and nothing you see after the reboot says Ubuntu. A MaluOS installer with its own screens is built in the repository and will replace it.
Continue at step 4.
3bOr boot the cloud image
The qcow2 image boots with cloud-init and provisions itself the same way. Give it user data the way your platform does: a NoCloud seed, OpenStack metadata, or Proxmox's cloud-init drive. The user data must at least create your user with an SSH key. A minimal example for plain KVM on a Linux workstation:
cat > user-data <<'UD'
#cloud-config
hostname: maluos-1
users:
- name: maluos
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA... you@example
UD
echo 'instance-id: maluos-1' > meta-data
cloud-localds seed.iso user-data meta-data
qemu-img create -f qcow2 -b maluos-26.04.20261028-server-amd64.qcow2 -F qcow2 disk.qcow2 40G
qemu-system-x86_64 -enable-kvm -m 4096 -smp 2 -drive file=disk.qcow2,if=virtio \
-drive file=seed.iso,if=virtio,format=raw -nic user,hostfwd=tcp::2222-:22
The first line creates a 40 GB disk backed by the image, so the download itself stays untouched. With the port forward above, the server is reachable as ssh -p 2222 [email protected] once it is up.
Optional: decide the provisioning before it happens. First boot reads /etc/maluos/firstboot.yaml. cloud-init can write that file before the provisioning service runs, which is how you set the tenant name, the administrator principal, or the Business OS domain for a server you will reach over the network:
#cloud-config
write_files:
- path: /etc/maluos/firstboot.yaml
content: |
tenant: {name: acme}
admin_principal: {ref: human:ops, kind: human, display_name: Ops, home_scope: org}
components:
maludb-os-core:
enabled: true
domain: maluos.acme.lan
scheme: http
admin_email: [email protected]
admin_name: Ops
Everything you leave out keeps its default. Continue at step 4.
3cOr add MaluOS to an existing Ubuntu 26.04 system
On a clean Ubuntu 26.04 server, the bootstrap script adds the signed package repository and installs the server metapackage. Read it first if you like; then:
curl -fsSL https://apt.maluos.com/bootstrap/install-maluos.sh | sudo bash
sudo reboot
Provisioning runs on the next boot. If you want the API server and the Business OS as well, install their metapackages before the reboot:
sudo apt install maluos-api maluos-business-os
Branding. The MaluOS branding package changes what the system calls itself (os-release, the login banner, GRUB). That is expected: the host becomes a MaluOS system. Do this on a machine you intend to run as MaluOS, not on a general-purpose Ubuntu box.
4Let the first boot finish
On its first boot the server runs maluos-firstboot.service once. It waits for PostgreSQL, creates the maludb database with the MaluDB extensions, the tenant (maluos by default), the administrator principal human:admin, the MCP listener with a generated token, and gives every human account a database login. Then it runs each component in order: the vault, the gateway, the API server and the Business OS kernel.
How long it takes. The core and the vault, gateway and API are ready within a couple of minutes. The Business OS kernel runs all of its database migrations and starts eight services, which takes a couple of minutes on a real machine or a KVM guest and up to 25 minutes under pure emulation. The unit allows up to two hours and resumes where it stopped if the machine is rebooted.
You can log in over SSH while this runs. The message of the day shows the provisioning state; to watch it live:
systemctl status maluos-firstboot
journalctl -u maluos-firstboot -f
What you should see: the unit ends as inactive (dead) with status=0/SUCCESS, and the file /var/lib/maluos/firstboot/done exists. On later boots the service sees that file and does nothing.
5Check the server
One command summarises what first boot made and whether it is healthy:
maluctl status
provisioned: 2026-10-29T09:12:41Z
database: maludb (maludb_core 0.106.0)
tenant: maluos
principal: human:admin
listener: http://127.0.0.1:5329 ok (user maludb-mc2dbd)
token: sudo maluctl token
operators: maluos
component: maluos-vault ok
component: maluos-gateway ok
component: maludb-api ok
component: maludb-os-core ok http://os.maluos.local
Every component should say ok. A component that says FAILED is recorded and does not stop the others; see If something is wrong. A few more checks that each part answers:
maluctl gateway status # backends, queue, expected waits, tiers
maluctl secret whoami # who the vault thinks you are (user:<your login>)
psql -d maludb -c 'select 1' # your own database login, created by first boot
sudo systemctl --failed # should list no units
6Get your tokens
Agents and tools that cannot use the local sockets authenticate with bearer tokens. First boot minted two and keeps them root-only under /var/lib/maluos/secrets:
sudo maluctl token # the MCP listener token (maludb-mc2dbd, port 5329)
sudo maluctl token api # the MaluDB API token (maludb-api, 127.0.0.1:8000)
Both services listen on localhost only. To reach them from another machine, put them behind a reverse proxy with TLS or an SSH tunnel; do not expose them as they are. sudo maluctl token rotate replaces the listener token and restarts the listener.
Your own secrets, such as a cloud model key, go into the vault rather than into files. Each person on the host has a compartment that only they can read; agents can be allowed to use a key without ever seeing it.
7Add a model
The gateway is already running, but the image does not carry a model runtime. Choose one or both:
A local model with Ollama
The gateway installs a pinned Ollama release as a localhost-only service and pulls the models you name. On a host without a GPU this works but is slow; the smallest default tier, fast, expects llama3.2:3b.
sudo maluctl gateway ollama install
sudo maluctl gateway ollama pull llama3.2:3b
sudo maluctl gateway ollama status
If the box has an NVIDIA RTX card, install the driver component first so Ollama uses it. The modules are signed for Secure Boot; a reboot loads them.
sudo apt install maluos-nvidia && sudo reboot
maluctl gpu status # after the reboot
A cloud model
Store the provider's key in the shared system compartment, let your user use it, and enable the backend. The key stays in the vault; the gateway attaches it per request.
sudo maluctl secret add system/anthropic --provider anthropic # prompts for the key
sudo maluctl secret grant system/anthropic --to user:$USER --level use
sudo maluctl gateway backend enable anthropic
Test it
maluctl gateway chat "Say hello from MaluOS." --model fast
maluctl gateway routes # which backend answered, and why
maluctl gateway usage # tokens and cost so far
What you should see: an answer, and a route row naming the backend (ollama-local or anthropic) and the concrete model. Callers ask for a tier (fast, standard, strong, embed) and the gateway picks the first healthy rung; sudo maluctl gateway catalog shows the ladder and lets you change it.
8Open the Business OS
The kernel serves its pages by name. With the default settings the names are os.maluos.local and app.maluos.local over plain HTTP, and the server resolves them to itself. Your workstation does not know them yet, so add the server's address to its hosts file (/etc/hosts on Linux and macOS, C:\Windows\System32\drivers\etc\hosts on Windows):
192.0.2.10 maluos.local os.maluos.local app.maluos.local
Replace the address with your server's. If you set a real domain in firstboot.yaml (step 3b), use that domain and point its DNS at the server instead.
First boot created the first super-admin with the email from the configuration ([email protected] by default) and a generated password, kept root-only on the server:
sudo cat /var/lib/maluos/secrets/business-os/admin-password
Open http://os.maluos.local in a browser and sign in with that email and password. What you should see: the Business OS login page served by the server's Apache, and after signing in, the organisation with its first two agents, the Installer and the JEV prompt writer, already hired.
Behind a TLS proxy. On a LAN plain HTTP is fine. For anything reachable from outside, put a reverse proxy with a certificate in front and set scheme: https for the component before first boot, so the kernel generates its URLs correctly.
9Keep it updated
Security updates from Ubuntu and MaluOS updates from apt.maluos.com install themselves through unattended-upgrades. To see what is pending and apply it now:
maluctl update status
sudo maluctl update apply -y
maluctl update history
Releases are the install media; a server you have installed receives new package versions through apt without reinstalling.
If something is wrong
maluctl statussays provisioned: no. First boot has not finished or failed. Readjournalctl -u maluos-firstboot; the log names the step. Every step is idempotent, so after fixing the cause (most often the network was not up, or the disk is full) run it again:sudo maluctl provision --force.- A component shows FAILED. The rest of the system is fine. The same journal shows the component's error;
sudo maluctl provision --forcere-runs all components safely. maluctl gateway chatsays no backend is available. No model is installed yet (step 7), or Ollama has not finished pulling:sudo maluctl gateway ollama status.- The Business OS page does not load. Check the name resolves to the server from your workstation (
ping os.maluos.local), and on the server that the kernel is healthy:curl -s http://127.0.0.1:8080/api/v1/health. - The unattended install asks for a new password. That is by design: the automated entry creates
maluos/maluosand forces a change at the first login. - Still stuck. Open an issue at github.com/maludb/maluos/issues with the output of
maluctl statusand the relevant journal lines.
What next
The server is ready to hold memory and run agents. The natural next steps, each a guide of its own on the way:
- Create your first agent.
sudo maluctl agent create NAME --exec /path/to/runmakes a Linux user, a principal, a vault compartment, a gateway policy and a hardened unit in one step;maluctl agent send NAME "…"talks to it. - Set up a desktop and enrol it with this server's office, so its agents use the office's models and applications.
- Join the estate.
sudo maluctl estate join URL --code CODEmakes this server a node that reports its health and, with a GPU, shares inference with the network.