Skip to content

Installation Reference ​

For your first cluster, follow Getting Started. This page covers installation flags, server requirements, and setup details.

kip install ​

Installs a production-ready Kubernetes cluster on a remote Linux server.

bash
kip install --host <ip> [flags]

Flags ​

FlagRequiredDefaultDescription
--hostYes—IP address or hostname of the target server. When kip identifies a single IPv4 address and confirms it is absent from the server's interfaces, as with a public address behind NAT, kip records it as the node's external address so DNS checks for custom domains use it. kip also advertises the API server on the source address of the server's route to that external address, usually its private address, so pods reach the API without a round trip through NAT. If kip cannot determine the source address, it preserves both settings. Re-running kip install applies these settings to an existing cluster and restarts k3s to load them
--ssh-keyNosee belowPath to SSH private key. Saved to ~/.kip/config.yaml so subsequent kip commands inherit it. If unset, kip reads KIP_SSH_KEY, then cluster.ssh_key from config; if still unset, ssh consults your ssh-agent and ~/.ssh/config as normal
--ssh-userNoSaved user for this host, otherwise rootUser to log in as. A user other than root needs passwordless sudo, and kip runs every command through sudo -n. Saved to ~/.kip/config.yaml as ssh_user, and used for every cluster node unless it has its own user set by kip node add --ssh-user. See Logging in as a user other than root
--domainNo<ip>.kipper.runThe name the cluster serves on. A *.kipper.run name (lab.kipper.run) is registered for you on the shared gateway; anything else is a domain whose DNS you run yourself, and whose hostnames have to resolve to the server before you install (see DNS for a domain you run). Omit it and the free name is derived from the server's address. See choosing your own name
--admin-emailNoadmin@<domain>Contact email for Let's Encrypt certificates. The admin login is always admin@<domain>, regardless of this setting. Defaults to admin@<domain> when --domain is a domain you run, otherwise admin@kipper.local
--orgNo—Organization short code (e.g. acme), used as namespace prefix
--org-display-nameNo—Human-readable organization name (e.g. Acme Inc)
--hardenNotrueDisable surplus host services exposed on public interfaces (e.g. rpcbind, Cockpit). Pass --harden=false only when you manage host security yourself
--admin-kubeconfigNofalseWrite the shared k3s admin certificate to this machine instead of a per-operator OIDC kubeconfig. The certificate is unattributed and revocable only by rotating the cluster CA. A CI escape hatch, not the everyday path
--no-loginNofalseSkip the inline browser sign-in during install. The machine ends up with a credential-free kubeconfig; the first operator runs kip auth login && kip auth verify afterwards
--credentials-fileNo—Save the generated admin email and password to a new file on the machine running kip. The path must differ from --result. Permissions are 0600 on Unix; Windows inherits the directory's permissions. Prints the file path on success or the credentials if saving fails. See What install writes to your machine
--firewallNotrueConfigure the host firewall with rules for k3s: UFW on Ubuntu and Debian, firewalld on Rocky Linux, AlmaLinux and CentOS Stream. Preserves active firewalls you manage unless you grant permission to take them over. Pass --firewall=false only when you manage host security yourself
--adopt-firewallNofalseAuthorize takeover of a running firewall without a Kipper ownership marker, after safety checks: UFW on Ubuntu and Debian, firewalld on Rocky Linux, AlmaLinux and CentOS Stream. Interactive SSH installs show the proposed changes and ask for permission, including with --via-server. Use this flag for unattended installs. It authorizes replacement of the rules (for firewalld, the public zone) present when takeover runs. Requires SSH or --via-server and is unavailable with --local. See Existing firewall detected
--no-ssh-rate-limitNofalseDisable UFW SSH rate limiting on Ubuntu and Debian. Kipper allows SSH without rate limiting on firewalld hosts. See below
--allow-ssh-passwordsNofalseLeave SSH password login as it is. By default, Kipper turns it off once a key-only login works. See Key-only SSH
--yesNofalseApprove migrating an existing cluster's pod network to WireGuard or recovering an interrupted migration. Migration restarts k3s, which makes the Kubernetes API unavailable for a short time (usually 10 to 30 seconds, longer on small or busy servers) while running containers keep serving; apps that call the API are affected for that time. Recovery may restore the previous configuration and restart k3s. When approval is needed, omitting this flag prompts in interactive installs or stops unattended installs before the network change
--localNofalseInstall on this machine; --host must reach it. See Installing on the server itself
--host-maps-hereNofalseWith --local: confirm that --host routes to this machine, such as through NAT
--resultNo—With --local: save a result file to import on your management machine with kip cluster add --install-result
--via-serverNotrue on WindowsRun a persistent install job on the server and stream its log. Enabled by default on Windows. See Installing from Windows
--server-kipNo—With --via-server: upload a local Linux kip binary; useful for unreleased builds
--cancelNofalseWith --via-server (the default on Windows): stop the running install on --host or discard its uncollected result
--dns-resolverNo1.1.1.1, 8.8.8.8, 9.9.9.9Upstream DNS resolver CoreDNS forwards external queries to. Repeatable, up to three IPv4 addresses (the resolv.conf nameserver limit; the cluster pod network is IPv4-only). Kipper forwards to reliable public resolvers instead of the host's /etc/resolv.conf, which varies by provider and can carry unreachable or rate-limited entries that break cluster DNS. The default sends your workloads' external DNS lookups to Cloudflare, Google, and Quad9. On private, split-horizon, or data-residency-sensitive networks, set your own resolvers (e.g. --dns-resolver 10.0.0.53), which is also how clusters resolve internal or corporate names. During install, Kipper checks each resolver is reachable from the server on port 53 and warns about any that are not
--profileNoSelected from RAM and CPUsSizing profile: nano, small, medium, large or xlarge. The default uses the server's RAM and CPU count. See Preflight checks. Existing clusters keep their recorded profile. To change it, use kip platform profile set
--storageNolocal for nano, longhorn otherwiseVolume storage: local keeps volumes on the server's disk and supports one node. Adding nodes requires longhorn. Existing clusters keep their storage mode. See Start Small with Nano
--trusted-proxyNo—IP or CIDR whose X-Forwarded-* headers Traefik honors. Repeatable. Set it when an external load balancer or proxy sits in front of the cluster, so apps and logs see real client addresses instead of the balancer's. The kipper.run gateway is trusted automatically; with no proxy in front, leave it unset and forwarded headers are ignored
--backup-storage-bucketNo—S3-compatible bucket name for Velero backups. When set, backups live off-cluster and survive a wipe. See External backup storage below
--backup-storage-regionIf bucket set—AWS region or provider equivalent. Use the actual region for AWS S3, auto for Cloudflare R2, whatever your provider expects elsewhere
--backup-storage-endpointNo—S3 endpoint URL. Omit for native AWS S3 (Velero derives it from the region). Required for R2, self-hosted MinIO, B2, Wasabi, DigitalOcean Spaces. Plain http:// is accepted only for a loopback, private, or link-local unicast address, localhost, a valid bare Service name, or a name ending in .svc or .svc.cluster.local. Hostnames are checked by syntax only
--backup-storage-credentialsNo~/.aws/credentialsPath to an AWS-style INI credentials file. Read only at install time and never stored back on disk
--backup-storage-profileNodefaultProfile name inside the credentials file. Lets you reuse an existing AWS CLI profile like acme without copying it to a separate file
--backup-storage-sse-cNoon where supportedRequire encryption of backup objects with a customer-provided key (SSE-C) that kip generates on the server, and fail when the store or bucket cannot support it. Without the flag, kip turns SSE-C on where it can and warns where it cannot. --backup-storage-sse-c=false turns it off. See SSE-C
--backup-storage-sse-c-key-fileTo recover from SSE-C backups—File containing the SSE-C key used to encrypt the bucket's backups, as saved by kip backup sse-key export, mode 0600
--backup-storage-read-onlyNofalseAttach the bucket for restores only, with both backup schedules off, to read the old bucket after kip backup storage set. Requires --backup-repository-key-file. See Read the old backups
--backup-repository-key-fileIf the bucket holds backups and the cluster has no key—File containing the key used to encrypt existing volume backups, mode 0600. See The backup repository key

DNS for a domain you run ​

--domain example.com puts the console on console.example.com, the API on console-api.example.com and the login on dex.example.com, and every app you deploy afterwards gets its own host under the same domain. cert-manager issues a Let's Encrypt certificate for each of those hosts and solves the HTTP-01 challenge against it, so each one has to resolve to the server.

One wildcard A record covers all of them, including the apps you have not deployed yet:

*.example.com.   A   203.0.113.10

Individual records work too, so long as console, console-api and dex exist before you install and you add another for every app you deploy afterwards.

The install looks up console, console-api and dex, including any per-host overrides, and warns when any of them do not resolve yet; it still continues, because DNS may only be minutes from propagating. The check asks only whether each name resolves somewhere, so a record pointing at the wrong address still passes. Separately, an install that ends in a browser sign-in waits up to five minutes for dex.example.com to answer its discovery URL over verified TLS, and tells you whether DNS or the certificate is what it is waiting for; if that never comes good it finishes anyway, with sign-in deferred. Four routes skip the wait: --admin-kubeconfig, --no-login, a run with no terminal, and a re-install by an operator whose session is still valid. Missing records still show up later as their own service failing: console. as a page that will not load, dex. as a sign-in that never completes, and console-api. as the kip commands that call the console API refusing to connect. The browser console is unaffected by that last one, because it reaches the API through /api on its own host.

Adding the record afterwards is enough on its own. cert-manager keeps retrying and issues once the hostnames resolve, and kip auth login finishes the sign-in that was deferred. See troubleshooting certificates.

Logging in as a user other than root ​

Cloud images from AWS, Google Cloud and Azure log you in as a default user such as ubuntu, admin or ec2-user and leave root login disabled. Pass that user with --ssh-user, and kip runs its commands through passwordless sudo, which those images grant the default user:

bash
kip install --host 203.0.113.10 --ssh-user ubuntu --ssh-key ~/.ssh/id_ed25519

The user is saved with the cluster, so kip upgrade, kip node add and the other commands that connect over SSH log in the same way. Every node of the cluster needs the same key. Use kip node add --ssh-user when a node's image needs a different login. For example, an AlmaLinux worker on AWS can join a Rocky Linux server with kip node add 203.0.113.11 --ssh-user ec2-user. kip records that user with the node, so later commands log in to it the same way. If sudo asks for a password, kip stops and names the user. --ssh-user cannot be used with --local, which already runs as root.

SSH rate limiting ​

The default UFW rule rate-limits new SSH connections to six in thirty seconds from one source address. Kipper normally shares one SSH connection during installation.

Turn it off with --no-ssh-rate-limit if your legitimate traffic can look like a burst:

  • CI that runs several kip commands in a row
  • Two or more people administering the server from the same office or VPN address
  • Any automation that opens SSH connections in quick succession
bash
kip install --host 203.0.113.10 --domain example.com --no-ssh-rate-limit

You can change your mind later:

bash
kip cluster harden --no-ssh-rate-limit

Kipper also skips the rate limit automatically when it cannot reuse a single connection throughout installation, for example when it cannot write to your home directory. The hundreds of connections needed in that case would hit the rate limit and lock Kipper out before installation finishes. Kipper displays a notice when it skips the limit. To add the limit later, run kip cluster harden from a machine where Kipper can reuse its SSH connection.

Installing on the server itself ​

For CI, cloud-init or a provider's user-data script, kip can run on the server and install it there, with no SSH connection at all:

bash
kip install --local --host 203.0.113.10 --result /root/cluster-result.kip

Run as root with HOME=/root. Set --host to the address other machines use to reach the server; kip uses it for the cluster's certificate and API address. Hostnames must resolve on the server, and loopback addresses are rejected. If the address is absent from local interfaces, as with public addresses behind NAT, confirm that it routes to this server when prompted. For unattended installs, pass --host-maps-here.

Local installs defer browser sign-in to your management machine. Copy the result file there and import it:

bash
kip cluster add --install-result --ssh-key ~/.ssh/id_ed25519 cluster-result.kip
kip auth login

--ssh-key records the local key path for maintenance commands such as kip upgrade, and --ssh-user records the login user when the server does not accept root logins. The result file holds the cluster's gateway credential and its settings, so keep it private and delete it once it is added. --install-result requires a new cluster name to protect existing entries. Run kip cluster uninstall from your management machine. It checks the recorded machine ID and local addresses to guard against uninstalling its own host.

What it installs ​

Preflight checks ​

Before installing, Kipper verifies:

  • OS: Ubuntu 22.04, 24.04 or 26.04, Debian 12 or 13, or Rocky Linux, AlmaLinux or CentOS Stream 9 or 10. Red Hat Enterprise Linux itself is not supported yet. Ubuntu 20.04 and Debian 11 pass the OS check with a warning: standard support has ended, and Kipper no longer tests these releases. A new cluster with Longhorn storage refuses Rocky Linux or AlmaLinux 9.7 or a later 9.x, and any EL9 kernel from 5.14.0-611, because Longhorn's volumes stop attaching there (Longhorn issue 13606). Use version 10, or hold the host at 9.6. Re-running the install on an existing cluster warns instead. See Longhorn upgrades.
  • RAM: 4 GB minimum. A 4 GB server reports less RAM because some memory is reserved by the host, so the installer accepts at least 3500 MiB of detected RAM. 2 GB servers run out of memory during installs and upgrades. The nano sizing profile disables monitoring. The installer recommends at least 8 GB for production workloads. A new cluster with Longhorn storage needs at least 6000 MiB, so a smaller server starts on local storage and grows onto Longhorn after a resize. An existing Longhorn cluster below 6000 MiB keeps installing and upgrading.
  • Disk with local storage: a new cluster needs at least 10 GiB free on the filesystem holding k3s's data (/var/lib/rancher/k3s), with a warning below 20 GiB. Volumes, images and system data share that space. On an existing cluster, disk shortages produce warnings so installation can continue.
  • Disk with Longhorn: preflight checks the filesystem holding Longhorn's data (/var/lib/longhorn, or /var/lib before installation). It budgets 20 GiB for fresh system volumes: 10 GiB for MinIO backups, 5 GiB for the Zot registry and 5 GiB for Loki logs. Disabling Loki saves 5 GiB, as the nano profile does by default. External backup storage saves another 10 GiB. The volume budget must fit within 70% of the filesystem, so the default setup needs at least 29 GiB of total capacity, or 22 GiB without Loki. After allowing for images and system data, more than 25% of the filesystem must remain free. The estimated installation footprint is 9 GiB with monitoring or 7 GiB without it, reduced by existing containerd usage. If k3s data is on a separate filesystem, preflight checks space for that footprint there. These checks use Longhorn's default thresholds. When kip install reads a saved platform profile, disk shortages produce warnings so the existing installation can be updated. A 40 GB disk with sufficient free space is a starting point. Allow extra capacity for apps, backups and expanded system volumes.
  • Kernel: the server must be able to load the wireguard kernel module. If it cannot, host preparation stops and names the missing module. For an existing VXLAN cluster with no unfinished network change, re-running kip install can keep VXLAN with a warning if WireGuard is unavailable. Normal k3s upgrade rules still apply. Joining workers with kip node add requires WireGuard.
  • Ports: 80 (HTTP), 443 (HTTPS), and 6443 (Kubernetes API) must not be in use by another service. The installer stops if something other than k3s, such as nginx or a Docker container, already listens on one of them

Kipper selects a sizing profile from detected RAM, using cutoffs of 6000, 7500, 15000, and 30000 MiB. Below 6000 MiB, monitoring is off by default to leave memory for the platform and apps. The higher cutoffs allow for memory reserved by the host. It then lowers the profile if estimated CPU requests leave less than 0.5 CPU for a default database service. For example, a server with 8 GB RAM and 2 vCPUs gets small. nano is the minimum, even when CPU capacity is insufficient.

Use --profile to choose a profile explicitly. Preflight warns if its estimated CPU requests leave too little room for a default database service. Existing clusters keep their recorded profile. If --profile specifies a different profile, the installer explains how to change it with kip platform profile set. See Sizing profiles for memory ranges and component allocations.

Plan for your workload

The preflight minimums let you install Kipper. Choose additional CPU, memory, and disk capacity for your apps, persistent data, monitoring, and backups. Leave room for image downloads, startup peaks, and overlapping pods during updates.

The AI bundle has its own memory and backup-storage checks. Measure performance with representative workloads before relying on a server size for production.

If you're on the small profile and need more room for apps, disabling the monitoring stack frees ~1-2 GB:

bash
kip platform disable prometheus
kip platform disable loki

The nano profile already disables monitoring. See Platform Resources for the full picture.

Components installed ​

ComponentPurpose
k3sLightweight Kubernetes distribution
TraefikIngress controller and reverse proxy
cert-managerAutomatic TLS certificates via Let's Encrypt
LonghornDistributed persistent storage for Longhorn clusters. Local storage uses k3s's local-path provisioner.
DexIdentity provider (OAuth2/OIDC)
Prometheus + GrafanaMetrics and dashboards (can be disabled)
LokiLog aggregation (can be disabled)
VeleroBackup and restore. Local-storage clusters require external backup storage to install Velero.
KEDAEvent-driven autoscaling
Kipper ConsoleWeb dashboard for cluster management

When an install fails ​

When an install step fails, kip install names the step and prints a link to a GitHub issue form. The link contains only details kip controls: the step, the kip version, your machine's OS, the server's distribution and version, the profile, and the names of the flags you set (without their values). Opening the link sends those details to GitHub to fill in the form. Submitting the form creates a public issue.

The last lines of the error appear below the link, between two marker lines, for you to paste into the form's Logs field. kip also tries to save a copy in a new install-error-*.txt file in ~/.kip and prints its path. If saving fails, kip reports that failure and the excerpt remains available on screen. Before printing the excerpt, kip replaces known addresses, domains, email addresses, non-root SSH usernames, passwords, tokens and backup keys from the install, along with IP addresses, hostnames, email addresses, home directory users and credentials matched by its detection rules. Those rules preserve public dependency hosts, loopback, link-local and unspecified addresses, and the k3s pod and service IP ranges unless they match a known value from the install. Redaction is best effort, so a bare machine name or a secret in an unusual format can slip through. Read the excerpt before pasting it. Only the text between the markers is redacted this way. The rest of the terminal output may still contain private data.

A server-driven install, the default on Windows, also prints the link and excerpt. Its link identifies kip as running on the server and omits the names of the flags you set because the server receives their values without a record of which flags you explicitly set.

A failure early in the install often comes from the server itself, such as a package manager still busy with first-boot updates. Wait a few minutes and re-run the same command.

Re-running install ​

Re-running kip install updates a component that is already there rather than duplicating it, and it keeps the serving identity recorded in the cluster (the domain and hosts for the console, API, and login) even when the cluster has moved to a different domain since the original install. Passing a conflicting --domain is an error: domain changes go through kip cluster domain, which keeps login available throughout the change.

kip upgrade is the routine way to catch a cluster up. Re-running the install is destructive in one specific way: it re-renders the Dex ConfigMap, which deletes every user account created through the console. Read what an upgrade moves before re-running it on a cluster that has any.

External backup storage ​

On a Longhorn cluster, Kipper installs an in-cluster MinIO by default and points Velero at it. This provides automatic backups with zero configuration, stored on the cluster's own storage. A kip cluster uninstall, a hardware failure, or anything that wipes Longhorn data also wipes the backup bucket.

A local-storage cluster needs external storage for backups, because a backup on the same disk would be lost if the disk failed.

For a cluster you care about, point Velero at off-cluster object storage instead. The bucket must already exist, kip does not create it.

Native AWS S3 ​

bash
kip install \
  --host 203.0.113.10 \
  --domain example.com \
  --backup-storage-bucket example-kipper-backups \
  --backup-storage-region eu-west-1 \
  --backup-storage-profile acme

--backup-storage-credentials defaults to ~/.aws/credentials. --backup-storage-profile defaults to default. Both [NAME] (the credentials file convention) and [profile NAME] (the config file convention) section headers are accepted.

Cloudflare R2 or other S3-compatible providers ​

bash
kip install \
  --host 203.0.113.10 \
  --domain example.com \
  --backup-storage-bucket example-kipper-backups \
  --backup-storage-region auto \
  --backup-storage-endpoint https://<accountid>.r2.cloudflarestorage.com \
  --backup-storage-credentials ~/r2-credentials

Same shape works for self-hosted MinIO, Backblaze B2, Wasabi, and DigitalOcean Spaces. Set --backup-storage-endpoint to your provider's S3 URL.

Credentials handling ​

The credentials file is read once at install time and never written to disk again. Kipper creates a Kubernetes Secret (cloud-credentials in the velero namespace) on the cluster, and the Velero HelmChart references that Secret by name. Your local kip config records the bucket, region, and endpoint but never the keys.

kip upgrade re-applies the Velero chart without rotating the secret, so you do not need to keep the credentials file around after install. To rotate keys, run kip install again with the updated credentials file pointing at the same host, which replaces the Secret in place. It re-runs the rest of the install as well, so read what an upgrade moves before doing it on a cluster with console-created users.

The backup repository key ​

Velero encrypts volume backups with a repository key. On a new cluster, kip install generates a random 32-byte key on the server before Velero starts, so the key never crosses the network. Resource definitions, such as Deployments and Secrets, are not encrypted by this key. On native AWS S3, they are encrypted at rest by the bucket, and on other stores kip encrypts them with SSE-C where the store supports it.

Save the key outside the cluster right after install, for example in a password manager:

bash
kip backup repository-key export --to ~/example-backups.key

Without the key, nobody can read the volume backups, including a new cluster you install to recover from them. Anyone with the key and read access to the bucket can read them all, so keep it as safe as the bucket credentials. The command asks for confirmation, writes a new file with mode 0600 and never overwrites an existing one. On Windows, the file inherits its folder's permissions, so save it inside your user profile. The key and the storage credentials carry Velero's exclude-from-backup label, so backups made from this release on do not contain them. A backup made earlier with --include-system can still hold them.

To replace the key, for example after it was exposed or on an older cluster that still uses Velero's published default, run kip backup repository-key reset. Backups written with the old key cannot be read with a new one, so the command deletes them. Every backup location shares the key, so the command supports clusters with exactly one location. It stops Velero and waits for the node agents to finish their transfers, then removes the backups, restores, Kopia and Restic repositories, and incomplete uploads from the bucket. Where the store lists object versions, it also deletes older versions. If the store cannot list versions, kip uses plain deletes and warns that it could not check older versions. If it cannot list incomplete uploads, kip warns that it could not check them. The command stops before deleting anything if the bucket's default retention locks every object or the bucket is known to be versioned and kip cannot list its versions. It also refuses a kip schedule that predates the exclusion of Dex's signing keys and sessions, because backups taken from that schedule would include them. Run kip upgrade first to update the schedules. If an earlier reset is unfinished, kip upgrade leaves Velero unchanged. In that case, the reset command adds the exclusion to kip's schedules before it starts Velero, finishes without taking backups, and asks you to run kip upgrade and then kip backup create. The reset command, kip install, and kip upgrade also reject Velero chart settings that kip does not manage, such as set overrides or a HelmChartConfig, because kip cannot tell when the Helm controller has applied them. If the backup location changes between the confirmation and the deletion, the command stops and starts Velero again with the old key. After cleanup, kip creates a new key on the server, restarts Velero and takes a full backup from each schedule. It asks for the bucket's name before deleting anything. Use --yes to skip the prompt.

A mirror of the bucket keeps its existing copies, each locked for at least the mirror's retention period. Their volume data needs the old key, so export it first if you may need them. After successfully stopping Velero, a failed run restarts it with the old key only when kip confirms that nothing was deleted. If Velero was already stopped, it stays stopped because an earlier run may have deleted part of the bucket. A failure after deletion starts leaves Velero stopped or running with the new key. Run the command again to finish. A run that reports the repository key as reset has finished, and only its new backups may still be running. Follow them with kip backup list. While a reset is unfinished, kip install refuses to set up backups on the same bucket, kip upgrade skips Velero, and kip node add leaves the Velero chart unchanged. Running kip install to move backups to another bucket starts Velero again with the old key, so run the reset again afterward. An object the store refuses to delete, such as one under its own retention lock, keeps Velero stopped until the store allows its deletion. A node that is down delays the command while it waits for the node agents. Recover that node's services with kip node fence first, then wait a minute before running the reset. A backup or drill started from another terminal during the reset is deleted along with the old backups.

When the cluster has no repository key, kip install requires the key used to encrypt any backups already in the bucket:

bash
kip install --host 203.0.113.10 --domain example.com \
  --backup-storage-bucket example-kipper-backups --backup-storage-region eu-west-1 \
  --backup-repository-key-file ~/example-backups.key

Outside Windows, the file must grant no permissions to other users, as SSH requires for a private key. The key must be a single line. A cluster keeps its key through upgrades and install re-runs. kip refuses a different key because replacing it would make existing volume backups unreadable. Clusters installed before this release keep the key Velero gave them.

Customer-provided encryption keys (SSE-C) ​

Some S3-compatible stores, such as Hetzner Object Storage, encrypt objects at rest only when the client sends its own key with every request (SSE-C). On such a store, kip install generates a random 32-byte key on the server, stores it in the Secret kipper-backup-sse-key in the velero namespace, and has Velero send it with every backup object it writes and reads.

By default, kip enables SSE-C when you pass external storage credentials to kip install, the cluster has no backup location or is moving to another bucket, the endpoint uses HTTPS, the bucket holds no backups, and the store passes the test below. An ineligible endpoint or bucket leaves SSE-C off with a warning. Native AWS S3 and upgrades without credentials use the behavior described below. A required bucket listing that fails stops the install because kip must know whether the bucket already holds backups. Pass --backup-storage-sse-c to require SSE-C and stop the install if it cannot be enabled:

bash
kip install --host 203.0.113.10 --domain example.com \
  --backup-storage-bucket example-kipper-backups --backup-storage-region hel1 \
  --backup-storage-endpoint https://objects.example.com \
  --backup-storage-sse-c

Enabling SSE-C requires HTTPS on an external S3-compatible store and a bucket without existing backups, unless you supply the key for existing SSE-C backups. Velero could not read objects written without the key after SSE-C is enabled. Before Velero starts, kip writes a test object with the key, reads it back, and checks that a HEAD request without the key returns HTTP 400 or 403. This rejects stores that ignore SSE-C and allow access without the key, preventing silent unencrypted backups. Without the flag, a failed write test leaves SSE-C off when the store serves the object without the key, returns different content when read with the key, or answers the keyed test write with Not Implemented and accepts the same write without the key. A test that could not run, for example after a timeout or a 503, stops the install. Native AWS S3 already encrypts backups with SSE-S3 and blocks SSE-C by default on new buckets, so kip leaves SSE-C off there and refuses the flag.

--backup-storage-sse-c=false turns SSE-C off for that run unless the cluster's backups already use it. For external S3-compatible storage, the install warns that Velero's own objects, including every backed-up Secret, remain unencrypted unless the store encrypts them itself. The choice applies only to the current run. It matters when creating a backup location or moving to another bucket because later runs preserve the running location's settings. Both forms of the flag require the storage flags in the same run, and =false cannot be combined with --backup-storage-sse-c-key-file. A cluster whose backups already use SSE-C keeps it because Velero needs the key to read them. Rerunning an install with storage credentials against the same bucket leaves existing plain backups plain and prints a warning because Velero could keep writing during the checks and switch.

An SSE-C key Secret that no backup location uses may still protect backups elsewhere. For example, it may remain after an interrupted install or a run with =false on a cluster that already held a key. kip keeps it unused with a warning unless the run requests SSE-C or qualifies for automatic activation. Automatic activation uses it only on an empty bucket after a successful write test. Failed activation only attempts to delete a key created in the same run.

If --backup-storage-sse-c-key-file supplies a different key, kip checks it with the write test and against any existing backup metadata before replacing the unused key. It first copies the old key to a Secret named kipper-backup-sse-key-previous-<UTC timestamp> in the velero namespace and reports that Secret's name. Save that key with kip backup sse-key export --previous <name> --to <file>. When a backup location uses the cluster's key, kip refuses a different key file because existing backups need the current key.

In-cluster MinIO stores backups without server-side encryption, and every install and upgrade that uses it prints a warning. Upgrades without storage credentials leave SSE-C as it is.

SSE-C covers the objects Velero writes itself: resource definitions such as Deployments and Secrets, backup logs and metadata. Kopia encrypts volume data with the backup repository key alone because it does not send the SSE-C key. kip backup list shows both protections below the list.

The install reminds you to save the key outside the cluster, next to the repository key:

bash
kip backup sse-key export --to ~/example-backups-sse.key

The file holds the key as base64 text. This key is required to read the objects protected by SSE-C, including when you install a new cluster to recover from them. A cluster keeps SSE-C and its key through upgrades and install re-runs, and moving it to another empty bucket repeats the test. To recover into a new cluster, pass both keys:

bash
kip install --host 203.0.113.20 --domain example.com \
  --backup-storage-bucket example-kipper-backups --backup-storage-region hel1 \
  --backup-storage-endpoint https://objects.example.com \
  --backup-repository-key-file ~/example-backups.key \
  --backup-storage-sse-c-key-file ~/example-backups-sse.key

Before Velero starts, kip checks the key against one existing backup's metadata using HEAD requests. It rejects a key that fails this check or backups accessible without an SSE-C key. A new cluster using a bucket with SSE-C backups requires the saved key. An upgrade also requires it if the cluster's key Secret is missing. These checks prevent either install from writing plain objects alongside encrypted ones.

To detect SSE-C backups, kip lists the bucket before Velero starts on a new cluster. A recovery install therefore needs storage credentials kip can use for listing, an endpoint without a path, and access and secret keys without : or @.

Velero's presigned downloads, such as velero backup logs and velero backup describe --details, omit the key and fail on an SSE-C bucket. kip backup describe fetches a backup's error and warning messages the same way, so on an SSE-C bucket it shows everything except those messages.

One-shot decision ​

Backup storage is chosen at install time. No command migrates a running cluster from one mode to another, and uninstalling to switch destroys your backups: in in-cluster mode they live on the cluster, so kip cluster uninstall removes them along with everything else and there is nothing left to restore from.

Re-running kip install with --backup-storage-bucket against the same host does repoint Velero at external storage, but it does not move the backups you already have, and it re-runs the rest of the install. Treat it as a change to make deliberately rather than a migration. The new bucket must be empty: kip refuses one that already holds backups, such as another cluster's, because Velero would take those backups over and later expire them.

The route that keeps your data is to install a second cluster with external storage from the start and move workloads onto it, taking anything you need off the first by a route that does not depend on its in-cluster backups. Both clusters can live in your config at once; switch between them with kip cluster use.

Sharing access with your team ​

After installing, you can give other developers access to the cluster without sharing SSH keys or server passwords. Invite each person, assign project membership, then export the cluster connection details:

bash
kip cluster export > my-cluster.kip

Team members import the file, sign in as themselves, and start working:

bash
kip cluster add my-cluster.kip --set-current
kip auth login
kip status

The export contains connection details and the public CA certificate. Each recipient signs in with their own account; permissions come from their role bindings and project membership.

Import creates a kubeconfig using Kipper’s credential plugin. It takes connection settings from the bundle and excludes executable plugins supplied by the sender. Existing kubeconfigs with credentials are preserved: move one aside deliberately if you intend to replace it.

The imported cluster name must be a valid plain name and must not conflict with another local kubeconfig.

See Team Access for the full workflow, including managing multiple clusters, database tunnels, and shell access.

What install writes to your machine ​

By default a fresh install writes a credential-free kubeconfig: it carries the cluster address and CA, and a kip auth kubectl-token exec plugin that serves your own short-lived OIDC token. The shared k3s admin certificate never leaves the server. At a terminal the installer signs you in inline and proves your identity works against the API server before finishing.

The admin account is printed first, because the sign-in asks for it.

  Admin sign-in
  Email:      admin@shop.kipper.run
  Password:   02026a371f24a488a86e654cada6e1c6

  Save these credentials now. They will not be shown again.
  If lost, run: kip auth reset-password

  Sign in to finish setup (a browser will open; Ctrl+C to skip and finish later with: kip auth login)
  kubectl authenticates as admin@shop.kipper.run: the admin certificate never left the server (break-glass: ssh, then sudo k3s kubectl)

To save the credentials to a file, pass --credentials-file <path>. The install checks the path before starting, then saves the credentials when they are available, before any sign-in prompt. It prints the file path in place of the credentials above. If saving fails, it prints the credentials so you can keep them.

Headless installs (CI, no terminal, or --no-login) finish credential-free without the sign-in; the first operator runs kip auth login && kip auth verify. The admin certificate reaches your machine only when you ask for it with --admin-kubeconfig, when an interactive install fails partway (so you can inspect the half-built cluster), or when sign-in genuinely fails to authorize against the cluster. Each case says so loudly.

Kubernetes and console API authentication ​

Most of kip talks to the Kubernetes API, so the certificate --admin-kubeconfig writes covers it: creating projects, adding services, deploying apps, reading logs, scaling, and everything kubectl does. A few commands go through the console API instead, which authenticates the operator rather than the kubeconfig, and they stop with not authenticated. Run: kip auth login:

  • kip service bind and kip service unbind
  • kip function bind and kip function unbind
  • kip app rebuild
  • kip service share
  • kip project allow-links and kip project links
  • kip auth sessions revoke-all

A pipeline holding only the certificate can therefore install a cluster, create a database and deploy an app, and connecting the two needs an operator to sign in once with kip auth login. The token that sign-in writes is what those commands read afterwards.

Next steps ​

See the CLI Reference for workload, cluster, and authentication commands.

See Upgrades & Maintenance for upgrade scope, options, and recovery.

Released under the Apache 2.0 License.