Skip to content

Profiles and config

The CLI keeps all its local state under ~/.flui/ and has three related topics for it:

  • Profiles (context topic). Each profile is one isolated Flui installation on this machine, with its own API URL, credentials and local inventory of clusters, nodes and firewalls.
  • The vault (vault topic). One passphrase per machine that seals every stored credential, in every profile.
  • Configuration (config topic). A layered resolver that decides the value of each preference and stores provider credentials, always inside the active profile.

If you only run one installation from this machine, the auto-created default profile is enough and you can ignore the context topic. You use config whenever you change an email, add a provider credential, or want to know why a preference has the value it has. You use the vault once to create it, then once per session to open it.

Profiles

A profile is a directory ~/.flui/profiles/<name>/. The CLI creates default on first run and remembers the active one in ~/.flui/context. Switching profile only changes local state. The cluster is not involved; the CLI points every following command at a different installation.

Commands

Terminal window
flui context list # all profiles, active one marked
flui context show # name of the active profile
flui context create staging # create a new profile
flui context create staging --switch # create and switch in one go
flui context use prod # switch to an existing profile
flui context delete staging # warns, deletes nothing
flui context delete staging --force # deletes it

Profile names accept alphanumeric characters, hyphens, and underscores. The default profile and the active one cannot be deleted.

The vault

Stored credentials are encrypted. A key kept in the profile directory, next to the data it protects, would give anyone who can read the folder both halves, so the key comes from a passphrase you know and this machine does not keep. That is the vault. There is one per workstation, and it covers every profile.

Terminal window
flui vault init # once per machine, before storing anything
flui vault unlock # once per session
flui vault status # is it open, and for how long
flui vault lock # close it now

flui vault init creates the vault and asks for a passphrase twice. It suggests a five-word one. The passphrase is never stored, cannot be derived from anything and cannot be reset, so losing it means losing every credential this machine has sealed. Write it down when you create it. If a vault already exists, init refuses to overwrite it, because that would make every sealed credential unreadable.

flui vault unlock asks for the passphrase once and then leaves a small background helper holding the key for the session. That helper is flui vault agent. It is a command only because that is how the CLI starts a copy of itself; it is hidden from help and you never run it by hand. It receives the passphrase through a pipe rather than as an argument, so the passphrase never appears in the process list.

Each profile has its own key, derived from the passphrase and the profile’s name. A command working in staging cannot open prod’s stored credentials.

The session closes on its own after thirty minutes of inactivity, and after eight hours in any case. Both limits are in minutes and can be changed:

VariableDefault
FLUI_VAULT_IDLE_MINUTES30
FLUI_VAULT_MAX_MINUTES480

Any value that is not a positive whole number falls back to the default, so a typo cannot make a session permanent. flui vault unlock --idle-minutes <n> --max-minutes <n> sets them for one session.

flui vault status tells you whether a vault exists, whether it is open, and how long each of those two clocks has left. --format json prints the same answer as { initialised, unlocked, location, idleRemainingMs, lifeRemainingMs }. It also warns you if other users on this machine can reach the helper’s socket. Keeping that socket private is the only thing that keeps them away from the key.

flui vault lock overwrites the key in memory and stops the helper. On a machine where nothing is open, it says so and does nothing.

A locked vault does not make every command fail. Most commands read a preference or an API URL, both plain text, and never ask for the passphrase. Only a command that opens a stored credential stops. It then says the vault is locked and names flui vault unlock, instead of reporting a decryption failure that would send you looking for corrupt data.

An upgrade locks nobody out

A profile that still holds the older .key file keeps working as before, so updating the CLI does not strand credentials you already have. The first flui vault unlock re-seals those profiles under the vault and deletes the old key file. Each entry is rewritten under the new key before the old one is removed, so an interrupted move loses nothing, and it reports how many secrets it moved. A profile it cannot move is left as it is, with a warning naming it.

Without a terminal

Both flui vault init and flui vault unlock take --stdin and read the passphrase from standard input instead of prompting. Use it in scripts. Without a terminal, both commands refuse to prompt and tell you to use --stdin.

Terminal window
printf 'my passphrase' | flui vault init --stdin
printf 'my passphrase' | flui vault unlock --stdin

Some callers have no terminal and no home directory that outlives the run, such as a provisioning worker. For them, setting FLUI_PROFILE_KEY to 32 bytes of base64 gives the CLI a profile key directly, and no vault is used:

Terminal window
export FLUI_PROFILE_KEY="$(openssl rand -base64 32)"

The key then lives only in whatever started the CLI. Anything the run sealed can no longer be opened once that caller forgets the key. A value that is present but malformed is an error; the CLI does not fall back to anything else.

Layered configuration

flui config reads and writes preferences and credentials. Every value goes through a cascade, and the first layer that has a value wins:

explicit CLI input > env var > ./flui.config.json > user-global config.json (active profile) > schema default

./flui.config.json is an optional file in the directory you run the command from, for preferences that belong to one project.

flui config show prints every preference with the layer its current value came from. Use it to debug an unexpected value:

Terminal window
flui config show

Preferences

Four preferences are declared in the schema:

KeyEnv varDefaultPurpose
emailFLUI_EMAIL(required)Contact email for Let’s Encrypt and operational notifications.
certificateModeFLUI_CERTIFICATE_MODEproductionCertificate issuance mode written into the dashboard config. One of production, staging, preflight. See TLS and certificates.
apiPathFLUI_API_PATH.Path to the flui-core repo. Only relevant to Flui contributors using env export-config / dev creds.
dashboardPathFLUI_DASHBOARD_PATH../flui-dashboardPath to the flui-dashboard repo. Same scope as apiPath.
Terminal window
flui config set email you@example.com
flui config set certificateMode preflight
flui config get email # resolved value + source

Preferences are not secrets and are stored in plain text, so reading or writing one never asks for the vault.

Provider credentials

flui config set <provider> stores the credentials needed to talk to a cloud provider’s API. The command works the same way for every provider. What differs is whether the credential is a single token or a key and secret pair. A single token can be passed inline; a pair goes through the interactive prompt, or a JSON object on --stdin:

ProviderCredentialInput
hetznerSingle API token (apiKey)Inline accepted: flui config set hetzner <TOKEN>
scalewayAccess Key ID + Secret KeyNot inline: flui config set scaleway prompts for both fields, or reads them as JSON with --stdin, and live-validates them against the Scaleway IAM API before saving
ovhOpenStack username + passwordNot inline: flui config set ovh prompts for both fields, or reads them as JSON with --stdin, and live-validates them against OVHcloud’s Keystone endpoint before saving

OVHcloud is addressed through OpenStack, so the credential is the username and password of a Public Cloud user (OVH Manager → Public Cloud → Users & Roles), not an OVH API application key. The password is shown once, at the moment the user is created. The user must have access to exactly one OpenStack project: Flui resolves the project from the credential itself, and stops if the credential reaches none or several.

These are the keys flui config accepts as providers. What each provider can do is in the providers table.

Storing a credential writes to the vault, so the vault must be unlocked. The exception is a profile that still holds the old key file, where that file’s key is used. A value passed as an argument is visible to every process on the machine through the process list, so --stdin is the safer way to pass one. For a provider with a credential pair, it is also the only way to configure it without a terminal, as a JSON object of its fields:

Terminal window
printf '%s' "$TOKEN" | flui config set hetzner --stdin
printf '{"accessKey":"…","secretKey":"…"}' | flui config set scaleway --stdin
printf '{"accessKey":"…","secretKey":"…"}' | flui config set ovh --stdin

For ovh, accessKey is the OpenStack username and secretKey the OpenStack password. The field names are the generic ones for a credential pair, shared with Scaleway.

Credentials are never printed back. flui config list shows which providers have credentials stored but not their values; flui config get works on preferences only, and says so if you ask it for a provider.

Terminal window
flui config set hetzner <YOUR_API_TOKEN>
flui config set scaleway # interactive prompt
flui config list # everything in the active profile
flui config list --tokens # provider credentials only
flui config list --preferences # preferences only
flui config list --verbose # with created/updated times
flui config test hetzner # read-only API call with the stored credentials
flui config remove hetzner # asks to confirm by retyping the key
flui config remove scaleway --force # skip the confirmation

flui config test <provider> checks the stored credentials with a real, read-only call to the provider and lists the servers, Flui-managed volumes and networks it finds on the account. It creates and changes nothing.

System keys

api-url is the only system-level key: the URL of the Flui API the active profile talks to. flui env create sets it, and flui env adopt, env sync and env status refresh it. You rarely need to edit it by hand; when you do, use flui config set api-url <url>. flui config remove api-url clears it.

What lives in a profile, and how it is stored

One file sits above the profiles:

  • ~/.flui/vault.json: the vault header, with the salt and a value that proves a passphrase is right. It holds no credential, and nothing in it helps anyone who does not know the passphrase.

A profile directory contains:

  • config.json: preferences (plain) and provider credentials (sealed under the vault).
  • .key: the pre-vault key file. Present only on a profile that has not been moved to the vault yet; the first flui vault unlock removes it.
  • ca/: the SSH CA used to authenticate to cluster nodes (sealed under the vault).
  • clusters.json, nodes.json, firewalls.json, vnets.json, operations.json: local inventory cached from the API. You can delete them; the next command that needs them fetches them again.

Examples

Terminal window
# Set the machine up once
flui vault init
flui vault unlock
# Create a staging workspace on Hetzner
flui context create staging --switch
flui config set email staging@example.com
flui config set hetzner <staging-token>
flui config set certificateMode staging
flui env create
# Same on Scaleway: interactive prompt for the key pair
flui context create staging-scw --switch
flui config set email staging@example.com
flui config set scaleway
flui env create --provider scaleway
# Same on OVHcloud: OpenStack username and password
flui context create staging-ovh --switch
flui config set email staging@example.com
flui config set ovh
flui env create --provider ovh --region GRA
# Debug where a preference is coming from
flui config show
flui config get certificateMode
# Remove a provider's credentials
flui config remove scaleway --force
# Finish for the day
flui vault lock

Multi-context CLI explains why the vault works this way: one passphrase over many installations, and what it does and does not defend against.