Bare Metal: OVHcloud
OVHcloud dedicated servers support custom iPXE boot, but — unlike latitude.sh — there is no field in the order form to paste a script into. You set the boot script through the OVH API instead. This page gives you a complete Go program that does the whole dance: set the script, reboot into it, then flip the server back to disk boot so it doesn't reinstall on every reboot.
See Working with Bare Metal for the general flow.
Step 1 — Create the iPXE script
Generate a one-time iPXE script for your host name. It is valid for 24 hours.
kheeper hosts ipxe create myorg/web-server
Copy the full #!ipxe … boot output — you'll paste it into the program below.
Step 2 — Get OVH API credentials
Create an application key, secret, and consumer key at OVH's token page for the region your server is in:
- EU servers: https://eu.api.ovh.com/createToken/
- US servers: https://api.us.ovhcloud.com/createToken/
- CA servers: https://ca.api.ovh.com/createToken/
Grant these rights so the program can read the server, set the boot script, and reboot:
GET /dedicated/server/*
PUT /dedicated/server/*
POST /dedicated/server/*/reboot
Save the credentials to ~/.ovh.conf. The endpoint must match the region
where you minted the token (ovh-eu, ovh-us, or ovh-ca), and the credential
section name must match that endpoint — this mismatch is the most common reason
the first call fails with This application key is invalid:
[default]
endpoint=ovh-eu
[ovh-eu]
application_key=xxxxxxxxxxxxxxxx
application_secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
consumer_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Step 3 — Run the program
Set up a module and add the official OVH client:
mkdir kheeper-ovh && cd kheeper-ovh
go mod init kheeper-ovh
go get github.com/ovh/go-ovh/ovh
Save the following as main.go. Edit the two consts at the top: server is
your dedicated server's name (e.g. ns1234567.ip-1-2-3.eu, shown in the
OVH control panel), and
bootScript is the script you copied in step 1.
package main
import (
"fmt"
"log"
"time"
"github.com/ovh/go-ovh/ovh"
)
// --- Edit these two values ---
// server is your OVH dedicated server's name from the control panel.
const server = "ns1234567.ip-1-2-3.eu"
// bootScript is the full output of `kheeper hosts ipxe create`. Keep the leading
// #!ipxe line and the trailing boot line.
const bootScript = `#!ipxe
# ... paste your kheeper iPXE script here ...
boot
`
// endpoint must match the region in your ~/.ovh.conf (ovh-eu, ovh-us, ovh-ca).
const endpoint = "ovh-eu"
func main() {
// Reads application_key / application_secret / consumer_key from the
// matching section of ~/.ovh.conf.
client, err := ovh.NewEndpointClient(endpoint)
if err != nil {
log.Fatalf("ovh client: %v", err)
}
// 1. Stage the custom iPXE script. Setting bootScript alone makes the
// server netboot it on the next reboot; OVH leaves bootId null. (You do
// NOT set a bootId here — that's only used to revert to disk, below.)
setScript := struct {
BootScript string `json:"bootScript"`
}{BootScript: bootScript}
if err := client.Put("/dedicated/server/"+server, setScript, nil); err != nil {
log.Fatalf("set bootScript: %v", err)
}
fmt.Println("set custom iPXE bootScript")
// 2. Reboot so the server netboots the installer.
var task struct {
TaskID int `json:"taskId"`
Function string `json:"function"`
Status string `json:"status"`
}
if err := client.Post("/dedicated/server/"+server+"/reboot", nil, &task); err != nil {
log.Fatalf("reboot: %v", err)
}
fmt.Printf("reboot task %d: %s (%s)\n", task.TaskID, task.Function, task.Status)
// 3. Wait for the server to PXE-boot and pull the installer into RAM, then
// revert to disk boot. This is the important step: once a bootScript is
// set, EVERY reboot netboots the installer — so when the install finishes
// and reboots, it would reinstall again, looping forever. Setting
// bootId=1 reverts to local-disk boot and clears bootScript, so the
// install's own post-reboot lands on the freshly installed disk.
fmt.Println("waiting 2m for netboot before reverting to disk boot...")
time.Sleep(2 * time.Minute)
revert := struct {
BootID int `json:"bootId"`
}{BootID: 1}
if err := client.Put("/dedicated/server/"+server, revert, nil); err != nil {
log.Fatalf("revert to disk boot: %v", err)
}
fmt.Println("reverted to disk boot; the install will boot from disk when it finishes")
}
Run it:
go run .
You'll see the boot script get set, a reboot task created, a two-minute pause, and then the revert to disk boot.
Step 4 — Verify
The install takes ten to thirty minutes. When it finishes, the machine boots from disk into the Kheeper base image and auto-registers:
kheeper hosts list --org myorg
You should see web-server in the list. Deploy to it like any other host — see
Working with Hosts.
Why the two-minute wait and revert? OVH serves the
bootScripton every network boot until you clear it. Without the revert, the server reinstalls each time the installer reboots and never comes up. Two minutes is enough for the server to fetch the installer over the network; after that it no longer needs the script, so it is safe to setbootId=1and let the install finish.
Further reading
- OVHcloud dedicated servers — product page and plans
- OVH API console — browse and try the
/dedicated/serverendpoints used above - Create an OVH API token — generate application key, secret, and consumer key
- OVH guide: custom iPXE scripts — OVH's own write-up of the
bootScriptflow go-ovh— the official OVH API client used by the program above