Skip to content

Product docsArm64 servers

Build multi-architecture Docker images on Arm64 and x86 servers

Publish one Docker tag for linux/amd64 and linux/arm64 by building natively on an Arm64 server and an x86 server with a two-node Buildx builder over SSH.

  • Advanced
  • 25 min read
  • Updated
On this page
  1. Before you start
  2. Step 1: Make both Docker engines reachable over SSH
  3. Step 2: Create one builder with two native nodes
  4. Step 3: Build and push both platforms
  5. Without a second server: emulation
  6. Write Dockerfiles that work on both
  7. Troubleshooting
  8. Next steps

A multi-platform image is one tag that contains a linux/amd64 and a linux/arm64 variant; Docker pulls the right one on each server. The fastest way to build one is natively: the arm64 half on an Arm64 VPS or VDS, the amd64 half on an x86 server, joined as two nodes of one Buildx builder. This guide sets that up over SSH.

Before you start

  • An Arm64 VPS or VDS and an x86 server (for example a Linux VPS), both with Docker Engine from Docker's repository; see install Docker on Ubuntu.
  • On both servers, a user that may use Docker (member of the docker group), reachable over SSH with a key; see SSH keys.
  • A build machine where you run the commands: one of the two servers, or your own computer with Docker and Buildx.
  • A container registry account; log in once with docker login registry.example.com.

In the examples, the x86 server is 203.0.113.20, the Arm64 server 203.0.113.30 and the user builder.

Step 1: Make both Docker engines reachable over SSH

On the build machine, create a Docker context for each server:

Bash
docker context create node-amd64 --docker "host=ssh://builder@203.0.113.20"
docker context create node-arm64 --docker "host=ssh://builder@203.0.113.30"
docker context ls

Verify: each context answers with the right architecture:

Bash
docker --context node-amd64 info --format '{{.Architecture}}'
docker --context node-arm64 info --format '{{.Architecture}}'

The first prints x86_64, the second aarch64.

Step 2: Create one builder with two native nodes

Bash
docker buildx create --use --name multi node-amd64
docker buildx create --append --name multi node-arm64
docker buildx inspect --bootstrap

Verify: docker buildx inspect lists two nodes, one with linux/amd64 and one with linux/arm64 among its platforms.

Step 3: Build and push both platforms

In the folder with your Dockerfile:

Bash
docker buildx build --platform linux/amd64,linux/arm64 -t registry.example.com/team/app:1.0 --push .

Buildx sends each platform to the node that builds it natively and pushes one tag with both variants.

Verify:

Bash
docker buildx imagetools inspect registry.example.com/team/app:1.0

The output lists the manifests for linux/amd64 and linux/arm64.

Without a second server: emulation

If you have only one server, Buildx can build the other architecture under QEMU emulation. Register the emulators once, then build as in Step 3 with the default builder:

Bash
docker run --privileged --rm tonistiigi/binfmt --install all

Expect compiled languages and large images to build many times slower than natively.

Write Dockerfiles that work on both

  • Use base images that are published for both platforms (most official images are).
  • Download architecture-specific files with the build arguments Buildx provides, such as TARGETARCH, instead of hard-coding amd64.
  • Compile with the toolchain inside the image, not by copying binaries built on your computer.

Troubleshooting

permission denied while trying to connect to the Docker daemon socket through a context. The SSH user is not in the docker group on that server; add it and log in again.

docker buildx inspect shows only one node. The --append step failed; check the context name with docker context ls and run it again.

exec format error during a RUN step. The build stage uses a binary for the wrong architecture, usually a downloaded file. Choose the file by TARGETARCH.

Push fails with unauthorized. Run docker login for the registry on the build machine.

Next steps

Frequently asked questions

Why not build everything with QEMU emulation?

Emulation works without a second server, but compiling under emulation is many times slower. With one native node per architecture, each half of the image builds at full speed.

Do I need Docker Desktop?

No. Docker Engine with the Buildx plugin, as installed from Docker's repository on Ubuntu and Debian, is enough on the build machine and on both nodes.

Where are the images stored?

In a container registry. A multi-platform build pushes one manifest list with both variants to the registry, so the build needs --push and a registry login.

Can a CI system use the same builder?

Yes. A self-hosted CI runner on the build machine can use the builder by name, as long as its user can reach both nodes over SSH with a key.

Generate Password

Please confirm