# 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.

Difficulty: Advanced

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](/guides/install-docker-ubuntu).
- On both servers, a user that may use Docker (member of the `docker` group), reachable over SSH with a key; see [SSH keys](/guides/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

- Arm64 basics: [Arm64 VPS and VDS: getting started](/guides/arm64-servers-getting-started).
- Run the images: [Docker Compose basics](/guides/docker-compose-basics).

## 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.

---

Source: <https://hyperdc.com/guides/products/multi-arch-docker-images>\
Updated: 2026-10-15
