This provides a method of statically compiliing nodejs for multiple architectures using Alpine Linux and Docker. Alpine Linux uses the musl library which allows for statically compiling Node. Docker provides the means to run Alpine Linux and also to emulate multiple architectures.
I've uploaded binaries that I've built locally to the Releases page. Binaries built with Github Actions (so you don't have to trust a random internet person) are coming soon!
The reason for this project comes from leafac/caxa#30. When packaging an application with caxa, it can be useful to provide a statically linked node binary to increase portability.
To produce a statically linked Linux binary on your local machine, run the following:
git clone https://github.com/maxb2/static-node-binaries.git
cd static-node-binaries
NODE_VERSION=v12.22.3 # Change this to the desired version
NPROCS=1 # Number of processes to use during compilation.
# NPROCS=$(nproc) uses all available processors
docker build --build-arg NODE_VERSION=$NODE_VERSION --build-arg NPROCS=$NPROCS -t static-node:$NODE_VERSION .
APP=$(docker run --rm -it -d static-node:$NODE_VERSION)
docker cp $APP:/usr/src/app/node/out/Release/node ./node-static-$NODE_VERSION
docker kill $APP
./node-static-$NODE_VERSION # Run the node binary
This produces the file node-static-v12.22.3
.
We can use docker to emulate other architectures such as ARM.
The most reliable way to do this is with buildx
.
Skip this step if you already have docker set up to emulate and build other architectures. First you must install buildx.
### Setup qemu for emulation
docker run --privileged --rm tonistiigi/binfmt --install all
### Create and use buildx driver
docker buildx create --use
### List available platforms
docker buildx ls
### Set parameters
PLATFORM='linux/arm64' # Platform to emulate. Choose one from the available platforms in `docker buildx ls`
NODE_VERSION=v12.22.3 # Desired node version.
NPROCS=1 # Number of processes to use during compilation.
# NPROCS=$(nproc) uses all available processors
### Compile
docker buildx build --platform $PLATFORM --load --build-arg NODE_VERSION=$NODE_VERSION --build-arg NPROCS=$NPROCS -t static-node:$NODE_VERSION .
### Extract binary
APP=$(docker run --platform $PLATFORM --rm -it -d static-node:$NODE_VERSION)
docker cp $APP:/usr/src/app/node/out/Release/node ./node-static-arm64-$NODE_VERSION
docker kill $APP
PLATFORMS='linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x' # Platforms to emulate.
NODE_VERSION=v12.22.3 # Desired node version.
NPROCS=1 # Number of processes to use during compilation PER PLATFORM.
docker buildx build --platform $PLATFORMs --load --build-arg NODE_VERSION=$NODE_VERSION --build-arg NPROCS=$NPROCS -t static-node:$NODE_VERSION .
Then, we extract the binary for a specific platform as follows.
Note: Do not use the
-t
or-it
flags with thedocker run
command below, as they cause binary files to be corrupted during thecat >
operation.
PLATFORM='linux/arm/v7'
IN='/usr/src/app/node/out/Release/node'
OUT=$(echo "node-static-$PLATFORM-$NODE_VERSION" | tr / -)
docker run --platform $PLATFORM --rm static-node:$NODE_VERSION cat "$IN" > "$OUT"