VPS KVM canadien à Montréal dès 8,50 CAD/mois

API

Recettes

Des scripts qui marchent : runner éphémère, flotte pilotée par le budget, extinction sur autonomie basse.

Trois scripts qui tournent. Ils tiennent en quelques lignes parce que l'API rend déjà les nombres sur lesquels décider : le solde, le débit, l'autonomie, le quota.

Tous supposent FFXF_TOKEN dans l'environnement et jq installé.

Un runner éphémère

Le cas d'école : une machine née pour une tâche, détruite à la fin. Coût réel d'un travail d'une heure sur un Nano : 0,018 CAD.

bash
#!/usr/bin/env bash
set -euo pipefail
API=https://api.ffxf.net/v1
AUTH="Authorization: Bearer $FFXF_TOKEN"
NOM="runner-$(date +%s)"

# Commander. La clé d'idempotence protège d'un double envoi sur reprise réseau.
VM=$(curl -sf "$API/vms" -H "$AUTH" -H "Content-Type: application/json" \
     -H "Idempotency-Key: $NOM" \
     -d "{\"plan\":\"nano\",\"region\":\"montreal\",\"image\":\"debian-13\",
          \"hostname\":\"$NOM\",\"billing\":\"hourly\",\"password_delivery\":\"none\",
          \"ssh_keys\":[\"$FFXF_SSH_FINGERPRINT\"]}" | jq -r .data.vm.id)

# Attendre la livraison : le provisionnement est asynchrone.
until [ "$(curl -sf "$API/vms/$VM" -H "$AUTH" | jq -r .data.status)" = "running" ]; do
  sleep 5
done
IP=$(curl -sf "$API/vms/$VM" -H "$AUTH" | jq -r .data.ipv4)

ssh -o StrictHostKeyChecking=accept-new "debian@$IP" "./ma-tache.sh"

# Détruire. Le nom d'hôte confirme : sans lui, l'API refuse.
curl -sf -X DELETE "$API/vms/$VM?confirm=$NOM" -H "$AUTH"

Notez password_delivery: none : aucune machine sans mot de passe n'est plus sûre qu'une machine dont le mot de passe traîne dans une boîte mail. Elle exige au moins une clé SSH.

Éteindre avant la panne sèche

L'API dit combien de temps le solde tient au débit actuel. Un script qui lit ce nombre n'a jamais de machine coupée par surprise.

bash
#!/usr/bin/env bash
# À passer toutes les heures. Sous 12 h d'autonomie, éteint les machines
# jetables pour que le crédit restant serve à celles qui comptent.
API=https://api.ffxf.net/v1
AUTH="Authorization: Bearer $FFXF_TOKEN"

AUTONOMIE=$(curl -sf "$API/account" -H "$AUTH" | jq -r '.data.hourly.runway_hours // 9999')

if (( $(echo "$AUTONOMIE < 12" | bc -l) )); then
  curl -sf "$API/vms" -H "$AUTH" \
    | jq -r '.data[] | select(.hostname | startswith("runner-")) | .id' \
    | while read -r vm; do
        curl -sf -X POST "$API/vms/$vm/actions" -H "$AUTH" \
             -H "Content-Type: application/json" -d '{"type":"shutdown"}'
      done
fi

Une machine éteinte continue d'être facturée : l'heure court tant que la machine existe, allumée ou non. Pour arrêter le compteur, il faut détruire. Ce script gagne du temps, il n'économise rien — remplacez shutdown par la suppression si c'est l'économie que vous cherchez.

Un inventaire qui coûte ce qu'il annonce

Le relevé par machine répond à la seule question qui se pose en fin de mois : laquelle coûte cher.

bash
curl -sf "https://api.ffxf.net/v1/usage?group_by=vm" -H "Authorization: Bearer $FFXF_TOKEN" \
  | jq -r '.data[] | [.hostname // "(détruite)", .hours, .amount] | @tsv' \
  | sort -k3 -rn

Les machines détruites y figurent avec leur nom : ce qu'elles ont coûté ne disparaît pas avec elles.

Gérer les refus proprement

Un script qui lit le code plutôt que le message survit aux reformulations et aux traductions.

bash
reponse=$(curl -s -w '\n%{http_code}' "$API/vms" -H "$AUTH" \
          -H "Idempotency-Key: $NOM" -H "Content-Type: application/json" -d "$CORPS")
corps=$(echo "$reponse" | head -n -1); code=$(echo "$reponse" | tail -n1)

case "$(echo "$corps" | jq -r '.error.code // "ok"')" in
  ok)                  echo "commandée" ;;
  insufficient_credit) echo "recharger $(echo "$corps" | jq -r .error.details.missing) CAD" ;;
  quota_reached)       echo "plafond atteint, détruire une machine ou écrire au support" ;;
  rate_limited)        sleep 60; exec "$0" "$@" ;;
  *)                   echo "refus : $corps"; exit 1 ;;
esac

Support & discussions

Questions techniques, retours d'incidents ou discussions d'infrastructure, l'équipe est présente sur Discord, Telegram, X et IRC.