How to Install and Setup Docker on Ubuntu 18.04. Docker is an open-source technology that is used to deploy applications through containers.It is a relatively new platform but is constantly updated and features a wide community of users. Improve this doc Balena base images. Balenalib is the central home for 26000+ IoT focused Docker images built specifically for balenaCloud and balenaOS.This set of images provide a way to get up and running quickly and easily, while still providing the option to deploy slim secure images to the edge when you go to production. Debian, Ubuntu, Raspbian Installing this package automatically starts and runs Caddy for you as a systemd service named caddy using our official caddy.service unit file. This package also comes with a caddy-api systemd service using our official caddy-api.service unit file, which is disabled by default. The Debian packages provided are used to configure the systemd unit, adding users and permissions. Docker container. Sudo systemctl daemon-reload sudo. The Debian packages provided are used to configure the systemd unit, adding users and permissions. Docker container. Sudo systemctl daemon-reload sudo.

balenalib is the central home for 26000+ IoT focused Docker images built specifically for balenaCloud and balenaOS. This set of images provide a way to get up and running quickly and easily, while still providing the option to deploy slim secure images to the edge when you go to production.

Features Overview

  • Multiple Architectures:
    • armv5e
    • armv6
    • armv7hf
    • aarch64
    • amd64
    • i386
  • Multiple Distributions:
    • Debian: jessie (8), stretch (9), buster (10), bullseye (11), and sid
    • Alpine: 3.9, 3.10, 3.11, 3.12 and edge
    • Ubuntu: xenial (16.04), bionic (18.04), cosmic (18.10), disco (19.04), eoan (19.10) and focal (20.04)
    • Fedora: 30, 31, 32, 33 and 34
  • Multiple language stacks:
    • Node.js: 15.7.0, 14.16.0, 12.21.0 and 10.23.1
    • Python: 2.7.18 (deprecated), 3.5.10, 3.6.12, 3.7.9, 3.8.6 and 3.9.1
    • openJDK: 7-jdk/jre, 8-jdk/jre and 11-jdk/jre
    • Golang: 1.16, 1.15.3 and 1.14.10
    • Dotnet: 2.1-sdk/runtime/aspnet, 2.2-sdk/runtime/aspnet, 3.1-sdk/runtime/aspnet and 5.0-sdk/runtime/aspnet
  • run and build variants designed for multistage builds.
  • cross-build functionality for building ARM containers on x86.
  • Helpful package installer script called install_packages inspired by minideb.

How to Pick a Base Image


When starting out a project, it's generally easier to have a 'fatter' image, which contains a lot of prebuilt dependencies and tools. These images help you get setup faster and work out the requirements for your project. For this reason, it's recommended to start with -build variants, and as your project progresses, switch to a -run variant with some docker multistage build magic to slim your deploy image down. In most cases, your project can just use a Debian based distribution, which is the default if not specified, but if you know the requirements of your project or prefer specific distros, Ubuntu, Alpine, and Fedora images are available. The set of balenalib base images follow a simple naming scheme described below, which will help you select a base image for your specific needs.

How the Image Naming Scheme Works

With over 26000 balenalib base images to choose from, it can be overwhelming to decide which image and tag are correct for your project. To pick the correct image, it helps to understand how the images are named as that indicates what is installed in the image. In general, the naming scheme for the balenalib image set follows the pattern below:

Image Names

  • <hw> is either architecture or device type and is mandatory. If using Dockerfile.template, you can replace this with %%BALENA_MACHINE_NAME%% or %%BALENA_ARCH%%. For a list of available device names and architectures, see the Device types.
  • <distro> is the Linux distribution. Currently there are 4 distributions, namely Debian, Alpine, Ubuntu and Fedora. This field is optional and will default to Debian if left out.
  • <lang_stack> is the programming language pack, currently we support Node.js, Python, OpenJDK, .Net, and Go. This field is optional, and if left out, no language pack will be installed, so you will just have the distribution and you can later install and use any language in your image/container.

Image Tags

Docker Debian Systemctl System

In the tags, all of the fields are optional, and if they are left out, they will default to their latest pointer.

  • <lang_ver> is the version of the language stack, for example, Node.js 10.10, it can also be substituted for latest.
  • <distro_ver> is the version of the Linux distro, for example in the case of Debian, there are 4 valid versions, namely sid, jessie, buster and stretch.
  • For each combination of distro and stack, we have two variants called run and build. The build variant is much heavier as it has a number of tools preinstalled to help with building source code. You can see an example of the tools that are included in the Debian Stretch variant here. The run variants are stripped down and only include a few useful runtime tools, see an example here. If no variant is specified, the image defaults to run
  • The last optional field on tags is the date tag <yyyymmdd>. If a date tag is specified, the pinned release will always be pulled from Docker Hub, even if there is a new one available.

Note: Pinning to a date-frozen base image is highly recommended if you are running a fleet in production. This ensures that all your dependencies have a fixed version and won't get randomly updated until you decide to pin the image to a newer release.



  • <hw> : raspberrypi3 - The Raspberry Pi 3 device type.
  • <distro> : omitted, so it defaults to Debian.
  • <lang> : node - the Node.js runtime and npm will be installed
  • <lang_ver> : 10.18 - This gives us Node.js version 10.18.x whatever is the latest patch version provided on balenalib
  • <distro_ver> : omitted, so it defaults to buster
  • (build run) : omitted, so the image defaults to the slimmed down run variant
  • <yyyymmdd> : omitted, we don't have a date frozen image, so new updates pushed to our 10.18 tag, for example patch versions from Node.js will automatically be inherited when they are available.


  • <hw> : i386 - the intel 32 bit architecture that runs on Intel Edison
  • <distro> : ubuntu
  • <lang> : python
  • <lang_ver> : latest points to the latest Python 2 version, which currently is 2.7.17
  • <distro_ver> : bionic is Ubuntu 18.04
  • (build run) : build - to include things like build-essential and gcc
  • <yyyymmdd> : 20191029 is a date frozen image - so this image will never be updated on Docker Hub.

run vs. build

For each combination of <hw>-<distro>-<lang> there is both a run and a build variant. These variants are provided to allow for easier multistage builds.

The run variant is designed to be a slim and minimal variant with only runtime essentials packaged into it. An example of the packages installed in can be seen in the Dockerfile of balenalib/armv7hf-debian:run.

The build variant is a heavier image that includes many of the tools required for building from source such as build-essential, gcc, etc. As an example, you can see the types of packages installed in the balenalib/armv7hf-debian:build variant here.

These variants make building multistage projects easier, take for example, installing an I2C node.js package, which requires a number of build time dependencies to build the native i2c node module, but we don't want to send all of those down to our device. This is the perfect time for multistage builds and to use the build and run variants.

Supported Architectures, Distros and Languages

Currently, balenalib supports the following OS distributions and Language stacks, if you would like to see others added, create an issue on the balena base images repo.

DistributionDefault (latest)Supported Architectures
DebianDebian GNU/Linux 10 (buster)armv5e, armv6, armv7hf, aarch64, amd64, i386
AlpineAlpine Linux v3.12armv6, armv7hf, aarch64, amd64, i386
Ubuntu18.04 LTS (bionic)armv7hf, aarch64, amd64, i386
FedoraFedora 32armv7hf, aarch64, amd64, i386
LanguageDefault (latest)Supported Architectures
Node.js15.7.0armv6, armv7hf, aarch64, amd64, i386
Python3.9.1armv5e, armv6, armv7hf, aarch64, amd64, i386
OpenJDK11-jdkarmv7hf, aarch64, amd64, i386, armv6
Go1.16armv7hf, aarch64, amd64, i386, armv6
Dotnet5.0-sdkarmv7hf, aarch64, amd64


Devices with a device type of raspberry-pi (Raspberry Pi1 and Zero) will be built from balenalib/rpi-raspbian and will be Raspbian base images. The raspberry-pi2 and raspberrypi3 device types Debian base images have the Raspbian package source added, and Raspbian userland pre-installed.

Not all OS distro and language stack versions are compatible with each other. Notice that there are some combinations that are not available in the balenalib base images.

  • Node.js dropped 32-bit builds a while ago so i386-based nodejs images (Debian, Fedora and Ubuntu) v8.x and v6.x are official. New series (v10.x and v12.x) are using unofficial builds.
  • armv6 binaries were officially dropped from Node.js v12 and v12 armv6 support is now considered unofficial.
  • The Node.js v6.x and v8.x series are not available for i386 Alpine Linux base images v3.9 and edge as node crashes with segfault error, we are investigating the issue and will add them back as soon as the issue is resolved.

Installing Packages

Installing software packages in balenalib containers is very easy, and in most cases, you can just use the base image operating system package manager. However to make things even easier, every balenalib image includes a small install_packages script that abstracts away the specifics of the underlying package managers, and adds the following useful features:

  • Install the named packages, skipping prompts etc.
  • Clean up the package manager metadata afterward to keep the resulting image small.
  • Retries if package install fails. Sometimes a package will fail to download due to a network issue, and retrying may fix this, which is particularly useful in an automated build pipeline.

An example of this in action is as follows:

This will run an apt-get update -qq, then install wget and git via apt-get with -y --no-install-recommends flags, and it will by default try this 2 times before failing. You can see the source of install_packageshere.

How the Images Work at Runtime

Each balenalib base image has a default ENTRYPOINT which is defined as ENTRYPOINT ['/usr/bin/']. This ensures that is run before your code defined in CMD of your Dockerfile.

On container startup, the script first checks if the UDEV flag is set to true or false. In the case where it is false, the CMD is then executed. In the case it is true (or 1), the will check if the container is running privileged, if it is, it will mount /dev to a devtmpfs and then start udevd. In the case the container is an unprivileged container, no mount will be performed, and udevd will be started (although it won't be very much use without the privilege).

At the end of a container's lifecycle, when a request to container restart, reboot or shutdown is sent to the supervisor, the balenaEngine will send a SIGTERM (signal 15) to the containers, and 10 seconds later it will issue a SIGKILL if the container is still running. This timeout can also be configured via the stop_grace_period in your docker-compose.yml.

Working with Dynamically Plugged Devices

Docker debian systemctl command not found

In many IoT projects, your containers will want to interact with some hardware, often this hardware is plugged in at runtime, in the case of USB or serial devices. In these cases, you will want to enable udevd in your container. In balenalib images this can easily be done either by adding ENV UDEV=1 in your Dockerfile or by setting an environment variable.

You will also need to run your container privileged. By default, any balenaCloud projects that don't contain a docker-compose.yml will run their containers privileged. If you are using a multicontainer project, you will need to add privileged: true to each of the service definitions for the services that need hardware access.

When a balenalib container runs with UDEV=1 it will first detect if it is running on a privileged container. If it is, it will mount the host OS /dev to a devtmpfs and then start udevd. Now anytime a new device is plugged in, the kernel will notify the container udevd daemon and the relevant device nodes in the container /dev will appear.

Note: The new balenalib base images make sure udevd runs in its own network namespace, so as to not interfere with cellular modems. These images should not have any of the past udev restrictions of the resin/ base images.

Major Changes

When moving from the legacy resin/.. base images to the balenalib ones, there are a number of breaking changes that you should take note of, namely:

  • UDEV now defaults to off, so if you have code that relies on detecting dynamically plugged devices, you will need to enable this in either your Dockerfile or via a device environment variable. See Working with Dynamically Plugged Devices.
  • The INITSYSTEM functionality has been completely removed, so applications that rely on systemd or openRC should install and set up the initsystem in their apps. See Installing your own Initsystem.
  • Mounting of /dev to a devtmpfs will now only occur when UDEV=on and the container is running as privileged. 1, true and on are valid value for UDEV and will be evaluated as UDEV=on, all other values will turn UDEV off.
  • Support for Debian Wheezy has been dropped.
  • armel architecture has been renamed to armv5e.

Installing your own Initsystem

Since the release of multicontainer on the balenaCloud platform, we now recommend the use of multiple containers and no longer recommend the use of an initsystem, particularly systemd, in the container as it tends to cause a myriad of issues, undefined behavior and requires the container to run fully privileged.

However, if your application relies on initsystem features, it is fairly easy to add this functionality to a balenalib base image. We have provided some examples for systemd and openRC. Please note that different systemd versions require different implementation so for Debian Jessie and older, please refer to this example and for Debian Stretch and later, please refer to this example.

Generally, for systemd, it just requires installing the systemd package, masking a number of services and defining a new and a balena.service. The Dockerfile below demonstrates this:

Building ARM Containers on x86 Machines

This is a unique feature of balenalib ARM base images that allows you to run them anywhere (running ARM image on x86/x86_64 machines). A tool called resin-xbuild and QEMU are installed inside any balenalib ARM base image and can be triggered by RUN ['cross-build-start'] and RUN ['cross-build-end']. QEMU will emulate any instructions between cross-build-start and cross-build-end. So this Dockerfile:

can run on your x86 machine and there will be no Exec format error, which is the error when you run an ARM binary on x86. This approach works only if the image is being built on x86 systems. Use the --emulated flag in balena push to trigger a qemu emulated build targetting the x86 architecture. More details can be found in our blog post here. You can find the full source code for the two cross-build scripts here.

This page describes various methods for installing Caddy on your system.


Download mac version 10.14

Our official packages come only with the standard modules. If you need third-party plugins, build from source with xcaddy or use our download page.



Static binaries

Simply downloading a Caddy binary does not install it as a service, but can be useful in dev or when upgrading an existing installation.

Debian Docker No Systemctl

  • View releases on GitHub (expand 'Assets')

Debian, Ubuntu, Raspbian

Installing this package automatically starts and runs Caddy for you as a systemd service named caddy using our official caddy.service unit file.


This package also comes with a caddy-api systemd service using our official caddy-api.service unit file, which is disabled by default. If you plan to configure Caddy solely through its API, then you should disable the caddy service, and enable the caddy-api service.

Stable releases:

Testing releases (includes betas and release candidates):

Fedora, RedHat, CentOS

Fedora or RHEL/CentOS 8:

RHEL/CentOS 7:



Linux service

Manually install Caddy as a service on Linux with these instructions.


Docker Ubuntu Systemctl Failed To Connect To Bus

  • caddy binary that you downloaded or built from source
  • systemctl --version 232 or newer
  • sudo privileges

Move the caddy binary into your $PATH, for example:

Test that it worked:

Create a group named caddy:

Create a user named caddy, with a writeable home folder:

If using a config file, be sure it is readable by the caddy user you just created.

Next, choose a systemd service file based on your use case:

  • caddy.service if you configure Caddy with a file.
  • caddy-api.service if you configure Caddy solely through its API.

They are very similar but have minor differences in the ExecStart and ExecReload commands to accommodate your workflow. Customize the file accordingly.

Double-check the ExecStart and ExecReload directives. Make sure the binary's location and command line arguments are correct for your installation! For example: if using a config file, change your --config path if it is different from our example.

The usual place to save the service file is: /etc/systemd/system/caddy.service

After saving your service file, you can start the service for the first time with the usual systemctl dance:

Verify that it is running:

When running with our official service file, Caddy's output will be redirected to journalctl:

If using a config file, you can gracefully apply any changes:

You can stop the service with:

Do not stop the service to change Caddy's configuration. Stopping the server will incur downtime. Use the reload command instead.


Note: This is a community-maintained installation method.


Note: This is a community-maintained installation method.

Linux and macOS:


You may need to adjust the Windows firewall rules to allow non-localhost incoming connections.


Note: This is a community-maintained installation method.

Coments are closed
Scroll to top