Custom images

Building a bespoke image for a Supported platform enables an Ubuntu Core device to be customised at the point of deployment. Customisation options include configuration for both hardware and software, specific kernels, and which snap packages to pre-install.

See Image building for an overview of building reference Ubuntu Core images for a supported platform.

Note: Building for non-reference architectures is also easily accomplished but requires upstream enablement. For further details, contact Canonical.


To build a custom image, first use the snapcraft command to login to the Snap Store:

$ snapcraft login

Snapcraft can be installed with sudo snap install snapcraft --classic, see Snapcraft overview for further details, and visit Create a developer account if you don't yet have an account.

Before creating a custom model assertion, you will need to retrieve your developer ID and generate a properly formatted timestamp. The snapcraft command can be used to retrieve your developer id:

$ snapcraft whoami
email: <email>
developer-id: bJzr2XzZ56Qv6Z51HIeziXvxtn1XItIq

Use the following date command to output the correctly formatted timestamp for the model assertion:

$ date -Iseconds --utc

Custom model assertion

The following is a tweaked JSON-structured custom model assertion based on ubuntu-core-18-amd64:

  "type": "model",
  "series": "16",
  "model": "ubuntu-core-18-amd64",
  "display-name":"Ubuntu Core 18 (amd64)",
  "architecture": "amd64",
  "kernel": "pc-kernel=18",
  "gadget": "pc=18",
  "base": "core18",
  "required-snaps": ["hello", "hello-world"],
  "authority-id": "bJzr2XzZ56Qv6Z51HIeziXvxtn1XItIq",
  "brand-id": "bJzr2XzZ56Qv6Z51HIeziXvxtn1XItIq",
  "timestamp": "2020-03-10T12:05:38+00:00"

We've saved the above example in a file called my-model.json, and it contains the following modified properties:

  • base: provides the run-time environment
    core18 is the current standard base and as is built from Ubuntu 18.04 LTS. See Base snaps for more details.
  • authority-id, brand-id: defines the authority signing the assertion
    reference assertions are signed by canonical. Non-reference assertions are signed by their brand store. For a custom model assertion, this needs to be the developer ID.
  • timestamp: UTC formatted time and date
    used to denote the assertion's creation time.
  • required-snaps: one or more snaps to be pre-installed for deployment any snap can be listed here. If there's a dependency on a different base, such as core, this will be installed too.

For a complete list of model assertion keywords, see Model assertion.

Signing a model assertion

The difference between building an image from a reference model assertion and building from a modified model assertion is that the modified model assertion needs to be digitally signed. This is accomplished in four stages:

  1. create a key
  2. export/register the key
  3. sign the model assertion
  4. build the image

Note: Rather than creating a key for every device, the same key is typically used across all models or model family.

First, sign in to the Snap Store (snap login) and check whether there is already a published key available. You can list any published snaps with the snap keys command:

$ snap login
Login successful

$ snap keys
No keys registered, see `snapcraft create-key`

If you have no registered keys, create one as follows:

$ snap create-key my-models
Confirm passphrase: <passphrase>

$ snap keys
Name         SHA3-384
my-key-name  E-n0AOKPFjIyy4S_i9JxTT4tkuaZf7rP9D2ARCmBNXjlgTGDjL8euFSlb87U0NPl

With a key created, use the snapcraft command to upload and register it with the store:

$ snapcraft register-key
Registering key ...

A custom model assertion is signed by piping the assertion through the snap sign command with the key name as its sole argument:

$ cat my-model.json | snap sign -k my-key-name > my-model.model

The resulting my-model.model file contains the signed model assertion and can now be used to build the image.

Building the image

With a signed model assertion, the Ubuntu Core image can now be built just like a reference image, using the ubuntu-image command:

$ ubuntu-image snap my-model.model
Fetching snapd
Fetching pc-kernel
Fetching core18
Fetching pc
Fetching hello
Fetching hello-world
Fetching core
WARNING: model has base "core18" but some snaps ("hello", "hello-world") require "core" as base as well, for compatibility it was added implicitly, adding "core" explicitly is recommended

As with when building a reference image, you can now use the image to boot either real or virtual hardware. See Building the image for more details.

From within a running session on a custom image, you can run the pre-installed snaps:

$ hello-world
Hello World!

Use snap list to see which snaps are installed:

$ snap list
Name         Version       Rev   Tracking  Publisher   Notes
core         16-2.43.3     8689  stable    canonical✓  core
core18       20200124      1668  stable    canonical✓  base
hello        2.10          38    stable    canonical✓  -
hello-world  6.4           29    stable    canonical✓  -
pc           18-2          36    18        canonical✓  gadget
pc-kernel    4.15.0-88.88  399   18        canonical✓  kernel
snapd        2.43.3        6434  stable    canonical✓  snapd

The snap known model command will show the read-only custom model assertion used to build the image:

$ snap known model
type: model
authority-id: bJzr2XzZ56Qv6Z51HIeziXvxtn1XItIq
series: 16
brand-id: bJzr2XzZ56Qv6Z51HIeziXvxtn1XItIq 
model: ubuntu-core-18-amd64
architecture: amd64
base: core18
display-name: Ubuntu Core 18 (amd64)
gadget: pc=18
kernel: pc-kernel=18
  - hello
  - hello-world
timestamp: 2020-03-10T12:05:38+00:00
sign-key-sha3-384: 9aZR3b1UX9kqiVVxzfUrKYzYjHX-gC8jGNc4hTCpGfpPyaFdWR7K68HLoY1EH3yR

© 2020 Canonical Ltd. Ubuntu and Canonical are registered trademarks of Canonical Ltd.