* docs: add work-in-progress Exoscale integration guide with stack diagrams * feat: source=exoscale external pool allocating Elastic IPs through the exo CLI * docs: rewrite the Exoscale guide as a short end-user install, and test the exo fake, store and wiring
title, seoTitle, description, category, tags, resources
| title | seoTitle | description | category | tags | resources | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Spinifex on Exoscale | Run Spinifex on Exoscale with Elastic IPs — Spinifex Docs | Install Spinifex on one Exoscale instance and run EC2, load balancers and EKS on real Exoscale Elastic IPs. | Install |
|
|
Running Spinifex on Exoscale
Warning
Work in progress. This page is not yet published on docs.mulgadc.com. Do not add it to
scripts/docs-config.jsoninmulga-docsuntil the Limits section is settled.
One Exoscale instance, the AWS APIs on its address, and guests reachable on real Exoscale Elastic IPs that Spinifex creates and deletes for you.
Table of Contents
What you get
A single Exoscale instance runs the whole Spinifex stack: EC2, EBS, S3, VPC, load balancers and EKS, behind an endpoint the ordinary AWS CLI, SDKs and Terraform provider talk to unmodified.
Whenever something needs a public address, such as an instance in a public subnet, an Elastic IP, an internet-facing load balancer or a NAT gateway, Spinifex creates an Exoscale Elastic IP, attaches it to your instance, and deletes it again when the resource goes away. You never manage the addresses by hand.
Before you start
You need:
- An Exoscale organisation and an API key that can create, attach, detach and delete Elastic IPs.
- An SSH key pair.
- The AWS CLI on your laptop.
Then create these in one zone, from the Exoscale console or the exo CLI. This guide uses de-fra-1.
| Resource | Setting |
|---|---|
| Compute instance | standard.huge (8 vCPU / 32 GiB) or larger, template Linux Ubuntu 26.04 LTS 64-bit, 100 GiB disk, your SSH key |
| Block storage volume | 256 GiB or more, attached to the instance |
| Security group | Allow all inbound TCP, UDP and ICMP from 0.0.0.0/0, attached to the instance |
Note the instance's ID (a UUID, shown on its page in the console) and the volume's ID. You do not need to create any Elastic IPs.
Note
The security group is open on purpose. Guests are filtered by their own Spinifex security groups, and the node by the Spinifex host firewall you turn on in step 5.
Install
Everything below runs on the instance, over SSH as ubuntu.
1. Check that the instance can run VMs
ls -l /dev/kvm && cat /sys/module/kvm_intel/parameters/nested
/dev/kvm must exist and the second line must print Y. If either fails, pick a different instance type before going further.
2. Put the data volume at /var/lib/spinifex
Every guest disk and S3 object lives here, so it belongs on the volume and not on the 100 GiB root disk.
VOL_ID=<volume ID>
DEV=/dev/disk/by-id/virtio-${VOL_ID:0:20}
sudo mkfs.ext4 -L spinifex-data "$DEV" # only on a new, empty volume
sudo mkdir -p /var/lib/spinifex
echo "UUID=$(sudo blkid -o value -s UUID "$DEV") /var/lib/spinifex ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab
sudo mount /var/lib/spinifex
findmnt /var/lib/spinifex # must print a line
3. Install the exo CLI and give it your key
Spinifex manages Elastic IPs by running exo, so it needs the CLI and a key file.
curl -fsSLO https://github.com/exoscale/cli/releases/download/v1.101.0/exoscale-cli_1.101.0_linux_amd64.deb
sudo dpkg -i exoscale-cli_1.101.0_linux_amd64.deb
sudo mkdir -p /etc/spinifex/exoscale
sudo tee /etc/spinifex/exoscale/exoscale.toml >/dev/null <<'EOF'
defaultaccount = "spinifex"
[[accounts]]
name = "spinifex"
key = "EXO..."
secret = "..."
defaultZone = "de-fra-1"
EOF
sudo chmod 700 /etc/spinifex/exoscale && sudo chmod 600 /etc/spinifex/exoscale/exoscale.toml
Check the key works: sudo exo --config /etc/spinifex/exoscale/exoscale.toml compute elastic-ip list -z de-fra-1.
4. Install Spinifex
curl -sfL https://install.mulgadc.com | sudo bash
sudo /usr/local/share/spinifex/setup-ovn.sh --management --nat-uplink
sudo spx admin init --node node1 --nodes 1 --region eu-central-1 --az eu-central-1a \
--ipsec=false --external-mode=nat
sudo chown -R spinifex-daemon: /etc/spinifex/exoscale
Now tell Spinifex where to get public addresses. Add this to the end of /etc/spinifex/spinifex.toml, just above the [bootstrap] section, using your instance ID:
[[network.external_pools]]
name = "exo"
source = "exoscale"
exoscale_zone = "de-fra-1"
exoscale_instance_id = "<instance ID>"
Leave the nat-transit pool that init wrote where it is.
Note
eu-central-1is the region name your AWS tools will see. It is your choice and does not have to match the Exoscale zone.
5. Turn on the firewall, then start
sudo env SETUP_STAGES=firewall /usr/local/share/spinifex/setup.sh --firewall on
sudo systemctl start spinifex.target
systemctl list-units 'spinifex-*' --no-pager
Every spinifex-* unit should be active. The daemon log confirms the Elastic IP integration is working:
sudo journalctl -u spinifex-daemon | grep -E 'exo CLI|Exoscale allocator ready'
6. Import an image
sudo spx admin images import --name ubuntu-26.04-x86_64 --config /etc/spinifex/spinifex.toml
For EKS, also import spinifex-eks-node. sudo spx admin images list --config /etc/spinifex/spinifex.toml shows the full catalogue.
Use it from your laptop
Copy the cluster's CA and the admin credentials from the instance:
NODE=<instance public IP>
mkdir -p ~/.spinifex
ssh ubuntu@$NODE 'sudo cat /etc/spinifex/ca.pem' > ~/.spinifex/exo-ca.pem
Copy the [spinifex] section of ~/.aws/credentials on the instance into your own ~/.aws/credentials as [spinifex-exo], then:
aws configure set --profile spinifex-exo region eu-central-1
export AWS_PROFILE=spinifex-exo AWS_CA_BUNDLE=~/.spinifex/exo-ca.pem
export AWS_ENDPOINT_URL=https://$NODE:9999
aws ec2 describe-regions # proves the connection
Launch an instance
aws ec2 import-key-pair --key-name demo --public-key-material fileb://~/.ssh/id_ed25519.pub
SG=$(aws ec2 describe-security-groups --filters Name=group-name,Values=default --query 'SecurityGroups[0].GroupId' --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr 0.0.0.0/0
AMI=$(aws ec2 describe-images --filters Name=name,Values='*ubuntu-26.04*' --query 'Images[0].ImageId' --output text)
aws ec2 run-instances --image-id "$AMI" --instance-type t3.small --key-name demo \
--query 'Instances[0].InstanceId' --output text
After about a minute, describe-instances shows a public IP. That is a new Exoscale Elastic IP, and it appears in the Exoscale console with a description beginning spinifex:.
ssh ubuntu@<public IP> 'curl -s ifconfig.me' # prints the same address
Terminating the instance deletes the Elastic IP at Exoscale.
Load balancers and EKS
The Terraform workbooks run unchanged. Pass the region and endpoint:
cd nginx-alb
terraform init
terraform apply -var region=eu-central-1 -var spinifex_endpoint=https://$NODE:9999
nginx-alb builds two web servers behind an internet-facing load balancer. eks-quickstart builds a Kubernetes cluster with one worker. Run terraform destroy before starting the next one, because of the quota below.
Important
Exoscale allows five Elastic IPs per organisation by default, and every public address Spinifex hands out uses one. An instance with a public IP uses one, an internet-facing load balancer one, a NAT gateway one, and
eks-quickstartthree. Past the quota,allocate-addressreturnsAddressLimitExceededand a launch returnsInsufficientAddressCapacity. Ask Exoscale support to raise it.Exoscale keeps counting a deleted Elastic IP for a while. After a
terraform destroy,exo limitsstill shows the old usage even thoughexo compute elastic-ip listno longer shows the addresses, so anapplystraight afterwards can hit the quota. Wait untilexo limitsagrees with the list before starting the next workbook.
Troubleshooting
A guest's public IP does not answer from the instance itself. That is expected: traffic from the host to a guest's Elastic IP is dropped. Test from your laptop.
SSH or HTTP is refused straight after launch. Guests take 30 to 60 seconds to boot. Wait and retry.
An EKS cluster goes to FAILED within seconds, or a load balancer never becomes active. Run exo limits. If Elastic IP usage is at the maximum, the cluster could not get its public endpoint; destroy it, wait for usage to drop, and apply again.
The daemon logs an exo error at start. Run the check at the end of step 3. A wrong key, secret or zone is the usual cause.
An Elastic IP you created yourself. Spinifex only ever touches Elastic IPs whose description starts with spinifex:<instance ID>:. Anything else in the organisation is left alone, but it still counts against the quota.
Limits
Proven on one standard.huge instance in de-fra-1 on 2026-09-30: EC2 with a public IP, Elastic IP allocate and release, the nginx-alb workbook and the eks-quickstart workbook with one worker. Each was reached from the internet and left no Elastic IP behind at Exoscale.
Not yet tested:
- More than one node. Each node would carry its own guests' Elastic IPs, with cluster traffic over an Exoscale private network.
- Moving an Elastic IP between nodes with its guest.
- A narrowly scoped API key. The proof used an unrestricted key.
- Other zones, bare metal and GPU instances.
- Guest disk performance on Exoscale block storage.