Skip to content

Dedicated instances

A dedicated instance is one complete Ophiolite for one organisation: its own server, its own PostgreSQL database and its own volumes, reached at its own address NAME.DOMAIN. One host runs several of them behind one host proxy, which obtains each address’s certificate and sends each request to the instance it names. Every instance starts with the public NLOG sample (well headers and a gamma-ray log) and one person, who receives a single-use sign-in link.

ophiolite-ops instance does all of it. The same commands this page shows are the ones the release’s qualification runs.

A trial host runs nothing else. The instances, their databases and the host proxy are the only services on it. No firewall is built between an instance and the host: an instance’s containers can reach its own database, the host proxy and DNS, and they could reach any other service listening on the host’s network addresses. On a host that runs nothing else there is nothing to reach. Instances cannot reach each other’s networks or databases.

init checks the rule: it asks, from a container on the host, whether any of the host’s listeners answers, and refuses while one does. Stop that service, or, when it must stay (an SSH server, say), record it as an exception:

Terminal window
python3 ophiolite-ops instance init --base-domain DOMAIN --proxy-image REF --allow-listeners 22

check asks again and names any listener that answers and is not an exception.

  • A Linux server with an x86_64 processor that runs nothing else (the host rule above), with at least 16 GB of memory and 40 GB of free disk.
  • Docker Engine with the Compose plugin, or rootless Podman 4.9 or later with Docker Compose 2.
  • Python 3.10 or later.
  • A domain for the instances, and a wildcard DNS A record (*.DOMAIN) that points at the server.
  • Ports 80 and 443 reachable from the internet, so the proxy can obtain certificates and people can reach their instance.
  • The Ophiolite release image on the server, by its digest (REGISTRY/ophiolite-server@sha256:DIGEST).

Each instance holds up to 3 GiB of memory (2 GiB for the server, 1 GiB for its database). The host refuses a new instance when the limits of all its instances would pass the memory budget (12 GiB by default, memory_budget_mib in host.json), or when its disk has less than 10 GiB free (disk_floor_mib).

Copy the tool out of the image, then claim the engine for one set of instances and start the proxy:

Terminal window
docker run --rm --network none --entrypoint cat REF /opt/ophiolite/package/host/ophiolite-ops > ophiolite-ops
python3 ophiolite-ops instance init --base-domain DOMAIN --proxy-image REF --allow-listeners 22

REF is the release image by its digest; DOMAIN is the domain of the wildcard record. --allow-listeners 22 records the SSH server you reach the host by as the one exception to the host rule; leave it out when nothing listens. The instances live under ~/ophiolite-instances (--root chooses another folder). One engine holds one such folder: a second init on the same engine is refused. On rootless Podman, give the proxy high ports (--http-port 8080 --https-port 8443) and forward 80 and 443 to them. Without that forwarding, people reach an instance at https://NAME.DOMAIN:8443, and that port is part of its address: the sign-in link and the message carry it. Choose the ports before the first instance; an instance keeps the address it was made with, and check reports one the proxy no longer serves.

Terminal window
python3 ophiolite-ops instance create alpha --email person@partner.example --organisation "Partner name" --image REF

This makes alpha.DOMAIN with the public sample and one person, and prints the message for that person: the address, the line “It is for public data only”, how long the trial runs (30 days) and a sign-in link that works once within 72 hours (--hours, at most 168). Send the message yourself, or add --send to send it through the host’s mail relay. The link is never stored: if it is lost or expires, make a new one:

Terminal window
python3 ophiolite-ops instance link alpha

A trial project’s name starts with “Trial, public data only”. --kind managed makes a workspace without that line.

A create takes about two minutes. The first time a name is served, the proxy also obtains its certificate, which can add up to three minutes; the create waits for it. When the certificate cannot be obtained, the create stops with “the proxy did not take the new configuration”: check that alpha.DOMAIN resolves to this host and that ports 80 and 443 are reachable from the internet. The proxy’s own log says which: docker logs on the container whose name ends in -proxy-proxy-1.

A create that stops leaves the instance unfinished; list shows it with the phase it reached. Remove it (as under “Remove an instance” below), then create it again:

Terminal window
python3 ophiolite-ops instance remove alpha --confirm alpha
python3 ophiolite-ops instance create alpha --email person@partner.example --organisation "Partner name" --image REF
Terminal window
python3 ophiolite-ops instance list

One line per instance under a header: its name, kind (trial or managed), state, the last step a create reached (linked when it finished), its release, its address and the next step when one is needed (a create that stopped, an upgrade that failed, a removal to finish). Every instance command first checks that the proxy serves exactly the instances that should be reachable, and corrects it.

Every operator command of a single deployment works inside one instance:

Terminal window
python3 ophiolite-ops instance run alpha -- backup before-review
python3 ophiolite-ops instance check alpha

check compares the instance’s sources with the sample it was created with and reports what changed.

Terminal window
python3 ophiolite-ops instance upgrade alpha NEW-REF
python3 ophiolite-ops instance upgrade --all NEW-REF
python3 ophiolite-ops instance proxy NEW-REF

An upgrade asks the new image whether it can start from the installed release, backs the instance up with the old image, switches its files and starts the server with the new image, then checks that the new release is installed. If the backup fails nothing changes. If the start fails, list shows it and the backup holds the instance as it was. --all upgrades one instance at a time and stops at the first failure; list then shows each instance’s release. The host proxy keeps running on the image it was started with; proxy moves it to the new image too, which is optional and can come later.

Terminal window
python3 ophiolite-ops instance export alpha

This makes the partner’s take-away: portable bundles of everything the first person can read, each checked after it is made, with MANIFEST.json naming every item as bundled or omitted, and why. Bundles hold the current revision of each item, not its history. The SDK opens them and another Ophiolite imports them. The bundles go to ~/ophiolite-instances/exports/alpha-TIME, which the tool prints; hand that folder to the partner, then delete it. A removal makes its own bundles for the archive, so an export is not needed before one.

Terminal window
python3 ophiolite-ops instance remove alpha --confirm alpha

The name is typed twice. The removal first writes what it will remove, then stops answering anyone but the operator, makes the bundles, takes a complete backup and checks it, and only then withdraws the address, stops the containers and deletes the volumes, the files this tool wrote and the instance’s line. The archive (~/ophiolite-instances/archive/alpha-TIME) holds the bundles, the backup and ARCHIVE.json, and is kept for 30 days. If anything fails before the archive is complete, nothing is deleted. If the removal is interrupted, run the same command again: it continues from where it stopped.

An instance that never started holds no data and is removed without an archive. Deleting an instance that holds data without an archive needs both --no-archive and --destroy-data.

The certificate of alpha.DOMAIN stays in the proxy’s volume and in public certificate logs.

Terminal window
python3 ophiolite-ops instance restore-archive ~/ophiolite-instances/archive/alpha-TIME alpha2
python3 ophiolite-ops instance prune-archives

restore-archive makes a new instance from an archive’s backup and gives its first person a new sign-in link. prune-archives deletes the archives past their 30 days and names each one. The archives kept are the folders in ~/ophiolite-instances/archive (ls ~/ophiolite-instances/archive); each one’s ARCHIVE.json says when its instance was removed.