How to use LXD with Juju

When your computer has LXD installed, Juju can operate the “localhost” cloud. The localhost cloud is a low cost alternative to a public cloud.

Juju supports the following versions of LXD:

  • juju v.2.9.x: lxd v.5.0
  • juju v.3.x.x: lxd v.5.x


Reasons to use Juju on localhost

  • creating a repeatable deployment: Juju enables you to quickly iterate to construct the optimal deployment for your situation, then distribute that across your team
  • local development: Juju’s localhost cloud can mirror the production ops environment (without incuring the costs involved with duplicating it)
  • learning Juju: LXD is a lightweight tool for exploring Juju and how it operates
  • rapid prototyping: LXD is great for when you’re creating a new charm and want to be able to quickly provision capacity and tear it down

If you would like to run Kubernetes workloads on your computer with Juju, we recommend MicroK8s with the MicroK8s cloud.


If you are looking to connect to a LXD server, rather than access an instance of LXD installed locally, read Adding a remote LXD cloud.

About LXD

LXD is an hypervisor that provides system containers that are secure, lightweight, and easy to use.


Need to install LXD? Visit the LXD docs for installation instructions.

Why not Docker?

Juju expects to see an operating system-like environment, so a LXD system container fits the bill. Docker containers are laid out for a singular application process, with a self-contained filesystem rather than a base userspace image.

Set up the localhost cloud

Configure LXD

Juju speaks directly to the local LXD daemon, which also requires lxd group membership.

newgrp lxd
sudo adduser $USER lxd

If you have not already done so, you will need to run lxd init to carry out from post-installation tasks. For most environments, using the default parameters is usually preferred:

lxd init --auto

There are several options, however. See the Getting Started with LXD webpage and the output from lxd init --help for more details.

Verify that the localhost is available

Our localhost cloud is now established. We can verify that by running juju clouds:

juju clouds

Juju should have detected the presence of LXD and added it as the localhost cloud:

You can bootstrap a new controller using one of these clouds...

Clouds available on the client:
Cloud     Regions Default   Type Credentials Source   Description
localhost 1       localhost lxd  1           built-in LXD Container Hypervisor

Deploy workloads

Workloads live within a “model” that is managed by the Juju controller.

Create a controller

Use the juju bootstrap command to provision a machine within LXD and create a controller running within it.

juju bootstrap localhost overlord

localhost and lxd can be used interchangeably. Standard practice is to also name your controller. In this instance we called it “overlord”.

The bootstrap process is highly configurable, but changing the settings is rarely required while evaluating Juju. See the Creating a controller page for further details.

During the bootstrap process, Juju connects with the LXD daemon, then provisions a machine to install the controller on.

Creating Juju controller "overlord" on localhost/localhost
Looking for packaged Juju agent version 2.9.x for amd64
Contacting Juju controller at 10.x.x.x to verify accessibility...

Bootstrap complete, controller "overlord" is now available
Controller machines are in the "controller" model
Initial model "default" added

Deploy a workload

The juju deploy command deploys a charm as an application. To explore how this works, see one or more of these tutorials:

Juju machines and LXD containers

There is a 1:1 correspondence between machine and container.

Adding a machine without any workload can be done as follows:

juju add-machine -n 1

Querying the available machines will now list the machine created in the previous command:

juju machines

The output from the machines query:

Machine  State    DNS            Inst id        Series  AZ  Message
0        started  juju-c795fe-0  focal       Running

Notice the “Inst id” column corresponds to the “NAME” column from LXC’s output:

lxc list
|     NAME      |  STATE  |         IPV4         | IPV6 |    TYPE    | SNAPSHOTS |
| juju-c795fe-0 | RUNNING | (eth0) |      | PERSISTENT | 0         |

Apply constraints

Juju constraints can be applied per controller or model workloads in the same way as other clouds. See Constraints and LXD containers for further details.


It’s important to note that, with LXD system containers, constraints are interpreted as resource maximums (as opposed to minimums).

Additional information

Simple bootstrap of a remote LXD server

From Juju 2.9.5, the easiest method for bootstrapping a remote LXD server is to add the remote to your local LXC config then bootstrap with juju.

On the remote server:

# ensure the LXD daemon is listening on an accessible IP
lxc config set core.https_address '[::]'
# give the LXD daemon a trust password so the client can register credentials
lxc config set core.trust_password mytrustpassword

On the bootstrapping client:

# add the remote LXD server to the local LXC config
lxc remote add myremote --password mytrustpassword
# bootstrap juju using the remote name in LXC
juju bootstrap myremote

The bootstrapping client must be able to reach the remote LXD containers. This may require the setup of a bridge device with the hosts ethernet device.

For more advanced setup of LXD with clusters and using Juju remotely see Using LXD with Juju - Advanced.

Non-admin user credentials

See Credentials for more details on how Juju credentials are used to share a bootstrapped controller.

To share a LXD server with other users on the same machine or remotely, the best method is to use LXC remotes. See Simple bootstrap of a remote LXD server above.

Add resilience via LXD clustering

LXD clustering provides the ability for applications to be deployed in a high-availability manner. In a clustered LXD cloud, Juju will deploy units across its nodes. For more, see Using LXD clustering with Juju.

Use LXD profiles from a charm

LXD Profiles allows the definition of a configuration that can be applied to any instance. Juju can apply those profiles during the creation or modification of a LXD container. For more, see Using LXD profiles with Juju.

LXD images

LXD is image based: All LXD containers come from images and any LXD daemon instance (also called a “remote”) can serve images. When LXD is installed a locally-running remote is provided (Unix domain socket) and the client is configured to talk to it (named ‘local’). The client is also configured to talk to several other, non-local, ones (named ‘ubuntu’, ‘ubuntu-daily’, and ‘images’).

An image is identified by its fingerprint (SHA-256 hash), and can be tagged with multiple aliases.

For any image-related command, an image is specified by its alias or by its fingerprint. Both are shown in image lists. An image’s filename is its full fingerprint, while an image list displays its partial fingerprint. Either type of fingerprint can be used to refer to images.

Juju pulls official cloud images from the ‘ubuntu’ remote ( and creates the necessary alias. Any subsequent requests will be satisfied by the LXD cache (/var/lib/lxd/images).

Image cache expiration and image synchronization mechanisms are built-in.

Juju-specific advice

Juju can make use of several advanced features within LXD. For details see Using LXD with Juju - Advanced. These features include:

  • Adding resilience to your models through LXD clustering
  • Registering a remote LXD server as a LXD cloud
  • Charms and LXD profiles

Next steps

Learn the core commands

Juju includes lots of functionality (see juju help commands for a full list). Here is a brief list of the most helpful commands to use when you are getting started:

  • juju dashboard provides a real-time web dashboard of all the models managed by the controller
  • juju status provides a view of a model, its applications, their units, and other resources
  • juju deploy deploys a new charm (or bundle) as (an) application(s) within a model
  • juju ssh allows you to access a secure shell into any machine or unit within the model
  • juju switch allows you to switch between models and controllers

Use juju help <command> for detailed usage instructions on every command provided by Juju.

Learn the core concepts

Becoming proficient in Juju requires learning some new terminology:

  • Models house applications.
  • Applications are “instances” of charms that are comprised of units. A unit occupies a machine. That machine may be also be used by other units.
  • Relations are a data exchange system between applications facilitated by the Juju controller.

This information is misleading since it is phrased that this command comes from the LXD host, which is not the case.

I would like to see link to a clear instruction on how to generate those LXD server side certificates and how to transfer it over to the juju client.

The command is: “juju autoload-credentials” and now-a-days with juju2.9, the output from that command is not like the one presented…

I’m not confident enough yet to give the full description on how to achieve it or I would have done it already. @pedroleaoc

Thanks, Erik. I will add this to the list of documents that require reviewing and ask someone from the team to check this info.

@erik-lonroth is the confusion between host and admin here?

Configure networking section was removed in a previous revision, but its (broken) link is still in the table of content.

1 Like

removed, thanks for letting us know

1 Like

These instructions look suspect:

newgrp lxd
sudo adduser $USER lxd

The first command is likely to fail if the second hasn’t already been run.

This is actually good, as the first command would also set the primary group to lxd for the spawned process, which will infect files that the user creates in that shell and all descendant processes. newgrp - is better.