This page installs a single Corium node on a Proxmox host, from the published qcow2. Every command and every output below comes from a real run on Proxmox VE 8.4.

The scripts in deploy/proxmox/ run on the Proxmox node itself, not on your laptop. This page does not use the web interface.

Before you start

  • A Proxmox host that you can reach over SSH as root. You run every command below on that host.
  • A storage that accepts snippets. local accepts them by default. To find out, run pvesm status --content snippets. If the command lists nothing, add snippets to the content types of a directory storage in Datacenter → Storage.
  • A free VMID. qm list shows the VMIDs in use.
  • Approximately 6 GB of free RAM and 32 GB of free disk.
  • The scripts from deploy/proxmox/ on that host. Step 4 runs create-vm.sh, and Proxmox does not ship it.
  • corium-agent on that host, if you want the validation in step 3. No release attaches it, so you build it from a checkout. The validation is optional, and nothing else on this page needs the binary.

You get both from the same clone:

git clone https://github.com/Corium-OS/Corium.git /root/Corium
cd /root/Corium
mise run build          # writes bin/corium-agent, for step 3

The paths below assume that clone. mise run build needs Go on the host. If you do not want Go on a hypervisor, do not run the build, skip the validation in step 3, and download only the script:

curl -fsSLO https://raw.githubusercontent.com/Corium-OS/Corium/v0.5.0/deploy/proxmox/create-vm.sh
chmod +x create-vm.sh

1. Fetch the qcow2

Run this on the Proxmox host, so that the file is where you need it:

cd /var/lib/vz/template
curl -fLO https://corium.b-cdn.net/corium-0.5.0-x86_64.qcow2

The release notes give the exact URL for each release, and the two other ways to download it. In a real run, 1.5 GB took 15 seconds.

2. Check what you downloaded

sha256sum /var/lib/vz/template/corium-0.5.0-x86_64.qcow2

Compare the result with the hash in the release notes. If they match, you have the bytes that the project published, not only a file that downloaded without an error. Downloads explains the chain that makes this true.

3. Describe the node

#cloud-config
corium:
  role: single
  cluster:
    name: homelab
users:
  - name: core
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: wheel
    shell: /bin/bash
    ssh_authorized_keys:
      - ssh-ed25519 AAAA... you@example.com
ssh_pwauth: false

Save it as /root/corium-node.yaml. The other install pages refer to this users: block. examples/single-node.yaml is the same document as a file that you can copy.

Before you boot anything, validate the document:

corium-agent validate /root/corium-node.yaml
/root/corium-node.yaml: valid (role single, cluster homelab)

4. Create the VM

Warning. If you set a static address, set NAMESERVER too. In Proxmox, ipconfig0 carries only an address and a gateway. So a node with a static address comes up with no resolver. The failure is confusing. The node answers ping and SSH works, but Kubernetes stops while it pulls images, with lookup quay.io: Try again. The script warns you, but only if you let it.

VMID=900 VM_NAME=corium \
  DISK_IMAGE=/var/lib/vz/template/corium-0.5.0-x86_64.qcow2 \
  CLOUD_CONFIG=/root/corium-node.yaml \
  MEMORY=6144 CORES=2 \
  /root/Corium/deploy/proxmox/create-vm.sh

The script imports the disk, resizes it, attaches the cloud-config as a custom cloud-init snippet, and stops:

unused0: successfully imported disk 'local-lvm:vm-900-disk-1'
  Size of logical volume pve/vm-900-disk-1 changed from 10.00 GiB to 32.00 GiB.
update VM 900: -cicustom user=local:snippets/corium-900.yaml
update VM 900: -ipconfig0 ip=dhcp

VM 900 (corium) created. Start it with:
  qm start 900

--cicustom lets the corium: block reach the node. It fully replaces the user-data that Proxmox generates, and does not merge with it.

The defaults are STORAGE=local-lvm, SNIPPET_STORAGE=local, BRIDGE=vmbr0, CORES=4, MEMORY=8192, DISK_SIZE=32G, and DHCP.

5. Start it and find it

qm start 900
qm guest cmd 900 network-get-interfaces

In a real run, the guest agent answered after approximately 30 seconds.

6. Watch it become a cluster

ssh core@<address>
$ corium-agent version
corium-agent 0.5.0 (a2575f3)

$ systemctl is-active corium-bootstrap k0scontroller
active
active

$ sudo k0s kubectl get nodes
NAME               STATUS   ROLES           AGE    VERSION
corium-f725a239    Ready    control-plane   2m1s   v1.36.4+k0s

In that run, the node took two minutes from qm start to Ready.

The configuration did not set a hostname, so the agent derived it from the machine ID. If you want to choose the name, set node.name.

role: single passes --no-taints, so the node schedules ordinary workloads. The node has no taints, and a pod runs without tolerations.

7. When you are done

qm stop 900 && qm destroy 900
rm /var/lib/vz/snippets/corium-900.yaml

qm destroy does not remove the snippet.

  • Downloads: the other ways to download an artefact, and how to verify one
  • cctl: manage this node without SSH, with its state, its journals, its upgrades, and a kubeconfig
  • Upgrades: move this node to a later image, and choose the tag to follow
  • Configuration: every field of the corium: block