Skip to content

Upgrading & Boot Order

For resilience purposes, the system has two software images referred to as the primary and secondary partition image. In addition, some bootloaders support netbooting.

The boot order defines which image is tried first, and is listed with the CLI show software command. It also shows the version installed per partition, and which image the system currently runs on. This order is automatically changed when updates are installed.

admin@example:/> show software
Boot order : primary secondary net

NAME       STATE     VERSION                DATE                     
primary    booted    v25.01.0               2025-04-25T10:15:00+00:00
secondary  inactive  v25.01.0               2025-04-25T10:07:20+00:00
admin@example:/>

Changing Boot Order

The boot order can be manually changed using the set boot-order command from the top-level admin-exec context in the CLI. This is useful for rolling back to a previous version or changing the preferred boot source.

The command accepts one to three boot targets as separate arguments, in the desired boot order. Valid boot targets are:

  • primary - The primary partition
  • secondary - The secondary partition
  • net - Network boot (if supported by bootloader)

The CLI provides tab-completion for boot targets, simplifying the process.

Example: View current boot order and change it:

admin@example:/> show boot-order
primary secondary net
admin@example:/> set boot-order secondary primary net
admin@example:/> show boot-order
secondary primary net
admin@example:/>

Example: Set boot order to only try primary partition:

admin@example:/> show boot-order
secondary primary net
admin@example:/> set boot-order primary
admin@example:/> show boot-order
primary
admin@example:/>

Example: Using tab-completion (press TAB to see available options):

admin@example:/> set boot-order TAB
net        primary    secondary
admin@example:/> set boot-order secondary TAB
net        primary    secondary
admin@example:/> set boot-order secondary primary
admin@example:/> show boot-order
secondary primary
admin@example:/>

The new boot order takes effect on the next reboot and can be verified with show boot-order or show software:

admin@example:/> show software
Boot order : secondary primary

NAME       STATE     VERSION                DATE                     
primary    booted    v25.01.0               2025-04-25T10:15:00+00:00
secondary  inactive  v25.01.0               2025-04-25T10:07:20+00:00
admin@example:/>

Note

The boot order is automatically updated when performing an upgrade. The newly installed image will be set as the first boot target.

Duplicate boot targets are not allowed. The CLI will reject attempts to specify the same target multiple times.

Upgrading

Upgrading the system is done one partition at a time. If the system has booted from one partition, an upgrade will apply to the other (inactive) partition.

  1. Download and unpack the release to install. Make the image pkg bundle available at some URL2
  2. (Optional) Backup the startup configuration
  3. Assume the unit has booted the primary image. Then running the upgrade command installs a new image on the secondary partition
  4. As part of a successful upgrade, the boot-order is implictly changed to boot the newly installed image
  5. Reboot the unit
  6. The unit now runs the new image. To upgrade the remaining partition (primary), run the same upgrade command again, and (optionally) reboot to verify the upgrade

Caution

During boot (step 5), the unit may migrate the startup configuration for any syntax changes. The migrated configuration is only applied to running-config, and the file on disk is kept as-is until you save it. Once saved, the old image on the other partition may not be able to read it, so upgrade the other partition as well after you have verified your setup. Until then, a note at login, in show software, and on the WebUI software page shows that the other partition has a different version.

The CLI example below shows steps 2-5.

Backup startup configuration: It is recommended to backup the startup configuration before performing an upgrade. The backup is useful if the upgrade fails, and makes a later downgrade a smoother process.

admin@example:/> dir /cfg
/cfg directory
backup/             ssl/                startup-config.cfg

admin@example:/> copy /cfg/startup-config.cfg /cfg/v25.01.0-startup-config.cfg
admin@example:/> dir /cfg
/cfg directory
backup/             ssl/                startup-config.cfg           v25.01.0-startup-config.cfg

admin@example:/>

Upgrade: Here the image pkg bundle was made available via TFTP.

admin@example:/> upgrade tftp://198.18.117.1/infix-aarch64-25.03.1.pkg
installing
  0% Installing
  0% Determining slot states
 10% Determining slot states done.
...
 40% Checking slot rootfs.1 (secondary)
 46% Checking slot rootfs.1 (secondary) done.
...
 98% Copying image to rootfs.1
 99% Copying image to rootfs.1
 99% Copying image to rootfs.1 done.
 99% Updating slots done.
100% Installing done.
Installing `tftp://198.18.117.1/infix-aarch64-25.03.1.pkg` succeeded
admin@example:/>

Reboot: The unit will boot on the other partition, with the newly installed image. The Loading startup-config step conducts migration of startup configuration if applicable.

admin@example:/> reboot
[ OK ] Stopping Static routing daemon
[ OK ] Stopping Zebra routing daemon
...
[ OK ] Loading startup-config
[ OK ] Verifying self-signed https certificate
[ OK ] Update DNS configuration
[ OK ] Starting Status daemon

Infix OS — Immutable.Friendly.Secure v25.03.1 (ttyS0)
example login: admin
Password:
.-------.
|  . .  | Infix OS — Immutable.Friendly.Secure
|-. v .-| https://www.kernelkit.org
'-'---'-'

Run the command 'cli' for interactive OAM

admin@example:~$ cli

See the 'help' command for an introduction to the system

admin@example:/> show software
Boot order : secondary primary net

NAME       STATE     VERSION                DATE                     
primary    inactive  v25.01.0               2025-04-25T10:15:00+00:00
secondary  booted    v25.03.1               2025-04-25T10:24:31+00:00
admin@example:/>

As shown, the boot order has been updated, so that secondary is now the preferred boot source.

To upgrade the remaining partition (primary), run the upgrade URL command again, and (optionally) reboot.

Unattended Software Updates

The system can check for new releases and install them on its own, on a schedule. Two features share one update source:

  • check-update logs a notice when a newer release is available, shown at the next login and on the WebUI dashboard
  • unattended-update also installs it, exactly like a manual upgrade

Enabling

The factory configuration names the release feed to follow and provides two schedules: nightly at 03:00 and weekly on Sunday nights at 03:00. Point a feature at a schedule to enable it:

admin@example:/> configure system
admin@example:/config/system/> set software check-update schedule nightly
admin@example:/config/system/> set software unattended-update schedule weekly
admin@example:/config/system/> leave

An installed release is activated on the next reboot, which by default is left to the operator. To reboot right after a successful install:

admin@example:/> configure system
admin@example:/config/system/> set software unattended-update reboot immediate
admin@example:/config/system/> leave

Set enabled false on a feature to pause it without losing its settings. A configuration that predates the factory schedules, or needs another maintenance window, can create its own.

Caution

An unattended update does exactly what a manual upgrade does: the new release goes to the inactive partition and the boot order is flipped, leaving the running partition as fallback should the new one fail to boot. Nothing else verifies the new release, see the caution under Upgrading about upgrading one partition at a time.

Status

show software lists the triggers and the outcome of the last run:

admin@example:/> show software
Boot order : primary secondary net

NAME       STATE     VERSION                DATE                
primary    booted    v26.08.1               2026-09-28T03:02:41Z
secondary  inactive  v26.08.0               2026-08-30T03:02:12Z

Software updates
  Source       : https://github.com/kernelkit/infix/releases.atom
  Check        : nightly (daily at 03:00)
  Unattended   : weekly (sunday at 03:00), reboot manual
  Last check   : 2026-09-30T03:00:12Z, latest v26.08.1, up to date
  Last install : 2026-09-28T03:02:41Z, installed v26.08.1, reboot pending

The same data is available under /system-state/software/update in the operational datastore, and on the WebUI dashboard. The log has the details:

admin@example:~$ grep unattended-update /var/log/messages
unattended-update: Installing v26.08.1 from https://.../infix-aarch64-v26.08.1.pkg (running v26.05.0)
unattended-update: Installed v26.08.1; reboot to activate the new image
Message Meaning
Installing <tag> from <url> (running <ver>) Install started
Installed <tag>; reboot to activate … Success, reboot manual
No update available (current: …, latest: …) Ran, nothing to do
Skipped: failed to query latest release … Feed unreachable
Another update is already in progress … Previous occurrence still running

Tip

A development build has no comparable version number and always counts as upgradable, so an unattended update on a dev build installs the latest release from the feed on the first occurrence.

Update Source

update-url names an RSS/Atom feed of releases. The factory configuration points it at the project's releases on GitHub:

admin@example:/> configure system
admin@example:/config/system/> set software update-url https://github.com/kernelkit/infix/releases.atom
admin@example:/config/system/> leave

Change it to follow a fork, or a feed of your own, see Hosting Your Own Feed.

The newest entry in the feed decides the latest version. Release candidates and other pre-releases are skipped unless allow-prerelease is set to true.

On each occurrence the feed is fetched, and a release newer than the one that boots next is installed by streaming its bundle straight from the server. Nothing is staged on disk, so no free space is needed, but the server must support HTTP range requests. Only one update runs at a time, an occurrence that fires while an install is still running is skipped.

Hosting Your Own Feed

Any static web server that honors HTTP range requests will do. The bundle is streamed rather than downloaded, so a server that ignores Range fails the install. BusyBox httpd and nginx both work, Python's http.server does not.

The feed is Atom or RSS 2.0, newest release first. Each entry links to its release page as <base>/releases/tag/<tag>, and that URL is all the device needs: the last path segment is the tag, the rest is the base from which the bundle is fetched by convention:

<base>/releases/download/<tag>/<image-id>-<tag>.pkg

where <image-id> is the running system's IMAGE_ID, e.g. infix-aarch64. The tag goes verbatim into the filename, and a tag containing -rc, -alpha or -beta counts as a pre-release. The release page itself does not have to exist, its URL only provides the tag, the download base, and a link in the update notice.

An Atom feed has one <entry> per release, each with a <link> whose href is the release page:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Example Infix releases</title>
  <entry>
    <title>v26.08.1</title>
    <updated>2026-08-20T10:00:00Z</updated>
    <link href="https://releases.example.com/infix/releases/tag/v26.08.1"/>
  </entry>
  <entry>
    <title>v26.05.0</title>
    <updated>2026-05-14T10:00:00Z</updated>
    <link href="https://releases.example.com/infix/releases/tag/v26.05.0"/>
  </entry>
</feed>

An RSS 2.0 feed carries the same URL as the text of each <item> element's <link>:

<?xml version="1.0"?>
<rss version="2.0">
  <channel>
    <item>
      <title>v26.08.1</title>
      <link>https://releases.example.com/infix/releases/tag/v26.08.1</link>
    </item>
  </channel>
</rss>

Atom is tried first. When no entry has a link with an href, the URLs are read from the text of each RSS item's link instead. Either way the first entry that passes the pre-release filter wins.

The example resolves bundles under https://releases.example.com/infix/releases/download/<tag>/, so lay the files out to match and name the feed whatever update-url points at. A device looks only for its own IMAGE_ID, so one feed can serve several platforms, with one bundle each per release:

infix/
├── releases.atom
└── releases
    └── download
        └── v26.08.1
            ├── infix-aarch64-v26.08.1.pkg
            └── infix-x86_64-v26.08.1.pkg

Then point the device at the feed:

admin@example:/> configure system
admin@example:/config/system/> set software update-url https://releases.example.com/infix/releases.atom
admin@example:/config/system/> leave

Tip

Serving the feed over HTTPS requires a correct clock on the device, or certificate validation fails and every occurrence is skipped. Plain HTTP avoids that on an isolated network.

Configuration Migration

The previous example shows a patch update from Infix v25.01.0 to v25.03.1. Between these versions, YANG configuration definitions changed slightly, more details given below.

During boot, the system inspects the version meta information within the startup configuration file to determine if configuration migration is needed. In this specific case, the configuration file has version 1.4 while the booted software expects version 1.5 (the configuration version numbering differs from the Infix image version numbering). The startup configuration is migrated to 1.5 definitions and applied to running-config, while a backup of the original startup configuration is stored in directory /cfg/backup/.

Important

The migrated configuration is only applied to running-config, the non-volatile startup-config is not touched. Migration is repeated on every boot until you confirm the upgrade as successful and save it:

admin@example:/> copy running-config startup-config

admin@example:/> dir /cfg/backup/
/cfg/backup/ directory                
startup-config-1.4.cfg

admin@example:/>

The file /cfg/startup-config.cfg itself is not changed. If the new image fails, the unit can fall back to the old image on the other partition, and its startup configuration is intact. The migration is repeated at every boot until the configuration is saved. Until then, a note at login says the configuration is not saved, and the WebUI shows unsaved changes, since the startup-config datastore reports the old version.

When you have verified the unit works as expected, save the migrated configuration:

admin@example:/> copy running-config startup-config
admin@example:/>

If the migration fails, the unit reverts to its failure config.

After saving, the modifications made to the startup configuration can be viewed by comparing the files from the shell. An example is shown below.

admin@example:/> exit
admin@example:~$ diff /cfg/backup/startup-config-1.4.cfg /cfg/startup-config.cfg
--- /cfg/backup/startup-config-1.4.cfg
+++ /cfg/startup-config.cfg
...
-          "public-key-format": "ietf-crypto-types:ssh-public-key-format",
+          "public-key-format": "infix-crypto-types:ssh-public-key-format",
...
-          "private-key-format": "ietf-crypto-types:rsa-private-key-format",
+          "private-key-format": "infix-crypto-types:rsa-private-key-format",
...
-    "version": "1.4"
+    "version": "1.5"
...
admin@example:~$

Downgrading

Downgrading to an earlier version is possible, however, downgrading is not guaranteed to work smoothly. In particular, when the unit boots up with the downgraded version, it may fail to apply the startup config, and instead apply its failure config.

A startup configuration of a newer version than the downgraded software supports is loaded as-is. It only fails if it uses settings the older version does not know.

We consider two cases: downgrading with and without applying a backup startup configuration before rebooting.

In both cases we start out with a unit running Infix v25.03.1, and wish to downgrade to v25.01.0.

admin@example:/> show software
Boot order : primary secondary net

NAME       STATE     VERSION                DATE                     
primary    booted    v25.03.1               2025-04-25T11:36:26+00:00
secondary  inactive  v25.03.1               2025-04-25T10:24:31+00:00
admin@example:/>

With Backup startup-config

This is the recommended approach to downgrade, given that you have a backup configuration available. The objective is to avoid ending up with the unit in failure config.

  1. Find the backup configuration file
  2. Run upgrade URL to install Infix image to downgrade to
  3. Copy backup startup configuration to current startup configuration (from shell)
  4. Reboot

Find the backup configuration file:

Assume you have a backup startup config for the Infix version to downgrade to (here Infix v25.01.0, config version 1.4).

The preferred approach is to use a startup configuration backed up when running Infix v25.01.0 on the unit. See section Upgrading above for more information. In the following example, there is a backup file available named v25.01.0-startup-config.cfg:

admin@example:/> dir /cfg
/cfg directory
backup/       ssl/       startup-config.cfg    v25.01.0-startup-config.cfg

admin@example:/>

The alternative is to use a startup config implicitly backed up by the system as part of Configuration Migration.

admin@example:/> dir /cfg/backup/
/cfg/backup/ directory
startup-config-1.4.cfg

admin@example:/>

Caution

Using a backup configuration file stored when the unit was running the old version (e.g., v25.01.0-startup-config.cfg) is preferred. Although backup files stored due to configuration migration (e.g., startup-config-1.4.cfg) usually works too if the configuration file version (1.4) matches, there are situations when the system may fail to apply it as described below.

The configuration file version (1.4) is only incremented when changes in YANG configuration syntax mandates it to handle upgrading. Say the next Infix version includes a new feature setting, it can still have version 1.4, as upgrading to it would not need migration. If a user then enables the new feature setting, the new configuration will no longer be compatible with the previous Infix version. A downgrade after enabling new features risks ending up with the unit in failure config.

Use upgrade command to downgrade:

admin@example:/> upgrade tftp://198.18.117.1/infix-aarch64-25.01.0.pkg
installing
  0% Installing
  0% Determining slot states
 10% Determining slot states done.
 ...
 99% Copying image to rootfs.1 done.
 99% Updating slots done.
100% Installing done.
Installing `tftp://198.18.117.1/infix-aarch64-25.01.0.pkg` succeeded
admin@example:/>

Apply the backup configuration file:

It is recommended to use a backup configuration file for the Infix version to downgrade to, if there is one available.

admin@example:/> copy /cfg/v25.01.0-startup-config.cfg /cfg/startup-config.cfg
Overwrite existing file /cfg/startup-config.cfg (y/N)? y
admin@example:/>

An alternative is to use a backup file stored when the system conducted a configuration migration. See the caution note above.

admin@example:/> copy /cfg/backup/startup-config-1.4.cfg /cfg/startup-config.cfg
Overwrite existing file /cfg/startup-config.cfg (y/N)? y
admin@example:/>

Reboot:

The unit will come up with the applied backup configuration.

admin@example:/> reboot
[ OK ] Saving system clock to file
[ OK ] Stopping Software update service
[ OK ] Stopping Status daemon
...
[ OK ] Bootstrapping YANG datastore
[ OK ] Starting Configuration daemon
[ OK ] Loading startup-config
[ OK ] Update DNS configuration
[ OK ] Verifying self-signed https certificate
[ OK ] Starting Status daemon

Infix OS — Immutable.Friendly.Secure v25.01.0 (ttyS0)
example login:

Note

If the unit despite these measures ends up in failure config, see the next section for more information on how to recover.

Without a Backup startup-config

This procedure assumes you have access to the unit's console port and its default login credentials1.

  1. Downgrade
  2. Reboot
  3. Login with unit's default credentials
  4. Conduct factory reset
  5. (Then go on configure the unit as you wish)

Use upgrade command to downgrade:

admin@example:/> upgrade tftp://198.18.117.1/infix-aarch64-25.01.0.pkg
installing
  0% Installing
  0% Determining slot states
 10% Determining slot states done.
 ...
 99% Copying image to rootfs.1 done.
 99% Updating slots done.
100% Installing done.
Installing `tftp://198.18.117.1/infix-aarch64-25.01.0.pkg` succeeded
admin@example:/>

Reboot:

Conduct a reboot. During boot, the unit fails to apply the existing startup configuration (config version 1.5 while software expects version 1.4 or earlier), and instead applies its failure config. This is what is seen on the console when this situation occurs. Note that the login prompt displays failed as part of the hostname.

admin@example:/> reboot
[ OK ] Saving system clock to file
[ OK ] Stopping Software update service
[ OK ] Stopping Status daemon
...
[ OK ] Verifying SSH host keys
[ OK ] Bootstrapping YANG datastore
[ OK ] Starting Configuration daemon
[FAIL] Loading startup-config
[ OK ] Loading failure-config
[ OK ] Verifying self-signed https certificate
[ OK ] Starting Status daemon

Infix OS — Immutable.Friendly.Secure v25.01.0 (ttyS0)

ERROR: Corrupt startup-config, system has reverted to default login credentials
failed-00-00-00 login:

To remedy a situation like this, you can login with the unit's default login credentials, preferrably via a console port. The unit's default credentials are typically printed on a sticker on the unit.

failed-00-00-00 login: admin
Password:

Run the command 'cli' for interactive OAM

admin@failed-00-00-00:~$

When it is safe from a network operations perspective, you can conduct a factory reset and reboot. It is recommended to remove the unit from any production network before doing this, as a factory reset may enable undesired connectivity between the unit's ports.

admin@failed-00-00-00:~$ factory
Factory reset device (y/N)? y
factory: scheduled factory reset on next boot.
Reboot now to perform reset, (y/N)? y
[ OK ] Saving system time (UTC) to RTC
[ OK ] Stopping mDNS alias advertiser
...
[ OK ] Starting Configuration daemon
[ OK ] Loading startup-config
[ OK ] Update DNS configuration
[ OK ] Verifying self-signed https certificate
[ OK ] Starting Status daemon
[ OK ] Starting Status daemon


Please press Enter to activate this console.

Infix OS — Immutable.Friendly.Secure v25.01.0 (ttyS0)
example login:

Continued configuration is done as with any unit after factory reset.


  1. In failure config, Infix puts all Ethernet ports as individual interfaces. With direct access, one can connect with e.g., SSH, using link local IPv6 addresses. This as an alternative to connecting via a console port. ↩

  2. Set up an FTP/TFTP/SFTP or HTTP/HTTPS server on the same LAN. ↩