Skip to main content

Run the AkôFlow server on a Linux instance

Use this how-to when an operator needs an AkôFlow control plane on a trusted Linux instance, rather than the local control plane installed by AkôFlow Desktop. It loads the daemon and BuildKit images directly from a versioned GitHub Release. It does not use a container registry and it does not install the Desktop application.

Use Install AkôFlow for a personal workstation. Do not use this procedure for an untrusted or multi-tenant host: the supplied Compose configuration gives the control plane access to the host Docker socket and runs BuildKit with Docker privileges.

Before you begin

You need:

  • a Linux amd64 or arm64 instance with Docker Engine and the Docker Compose v2 plugin installed;
  • an account allowed to download the public GitHub Release assets;
  • shell access to the instance and enough disk space for the two image archives, their loaded images, BuildKit state, SQLite data, and workflow artifacts;
  • a firewall or private network policy that keeps port 8080 reachable only from the operator or a reverse proxy you manage.

This guide keeps the API bound to 127.0.0.1 on the instance. Reach it through an SSH tunnel or terminate TLS at a separately managed reverse proxy. Do not change the port mapping to 0.0.0.0 merely to make it convenient: bearer-token authentication protects operations, but the service is a control plane with access to Docker, workflow credentials, and execution targets.

The release must contain matching daemon and BuildKit archives for the instance architecture. A missing archive means that release cannot be used for this deployment.

1. Select the Release and architecture

On the instance, choose the exact release tag and map the kernel architecture to the name used by the Release assets.

export AKOFLOW_RELEASE_TAG="v1.0.4" # replace with an existing release tag

case "$(uname -m)" in
x86_64) export AKOFLOW_ARCH="amd64" ;;
aarch64|arm64) export AKOFLOW_ARCH="arm64" ;;
*) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
esac

Confirm that the exact release lists these three files before continuing:

akoflow-daemon-<tag>-linux-<arch>.tar
akoflow-buildkit-<tag>-linux-<arch>.tar
akoflow-runtime-<tag>-linux-<arch>.sha256

The Downloads and Releases page explains the relationship between the Git tag and published artifacts. This procedure deliberately uses the two runtime archives; it does not look for a package or a registry image.

2. Download and verify the runtime images

Create a directory owned by the service operator. The checksum manifest and both image archives must stay together while sha256sum verifies them.

mkdir -p ~/akoflow-server/releases
cd ~/akoflow-server/releases

export AKOFLOW_RELEASE_URL="https://github.com/UFFeScience/akoflow/releases/download/${AKOFLOW_RELEASE_TAG}"

curl --fail-with-body --location --remote-name \
"${AKOFLOW_RELEASE_URL}/akoflow-daemon-${AKOFLOW_RELEASE_TAG}-linux-${AKOFLOW_ARCH}.tar"
curl --fail-with-body --location --remote-name \
"${AKOFLOW_RELEASE_URL}/akoflow-buildkit-${AKOFLOW_RELEASE_TAG}-linux-${AKOFLOW_ARCH}.tar"
curl --fail-with-body --location --remote-name \
"${AKOFLOW_RELEASE_URL}/akoflow-runtime-${AKOFLOW_RELEASE_TAG}-linux-${AKOFLOW_ARCH}.sha256"

sha256sum --check "akoflow-runtime-${AKOFLOW_RELEASE_TAG}-linux-${AKOFLOW_ARCH}.sha256"

Every checked file must report OK. Stop if a checksum fails; remove the downloaded files and obtain them again from the same release.

Load the verified images into the instance's local Docker image store:

docker image load --input "akoflow-daemon-${AKOFLOW_RELEASE_TAG}-linux-${AKOFLOW_ARCH}.tar"
docker image load --input "akoflow-buildkit-${AKOFLOW_RELEASE_TAG}-linux-${AKOFLOW_ARCH}.tar"

docker image inspect \
"akoflow/daemon:${AKOFLOW_RELEASE_TAG}" \
"akoflow/buildkit:${AKOFLOW_RELEASE_TAG}" \
--format '{{.RepoTags}}'

The last command must print both versioned image tags. The Compose stack uses only those local tags, so it cannot silently pull a newer image.

3. Configure the local control plane

Download the versioned Compose file supplied with this documentation:

cd ~/akoflow-server
curl --fail-with-body --location --remote-name \
"https://akoflow.com/examples/server-instance/compose.yaml"

Create a private .env file. Generate the bearer token on the instance and store it in the operator's password manager; it is required by every operational API request. The shell commands below avoid putting the token in the shell history.

umask 077
read -r -s -p "AkôFlow API token: " AKOFLOW_API_TOKEN
printf '\n'
printf 'AKOFLOW_RELEASE_TAG=%s\nAKOFLOW_API_TOKEN=%s\nAKOFLOW_PORT=8080\n' \
"$AKOFLOW_RELEASE_TAG" "$AKOFLOW_API_TOKEN" > .env
unset AKOFLOW_API_TOKEN

The Compose file persists SQLite, managed credentials, simulation workspaces, artifacts, and BuildKit state in named Docker volumes. It disables the interactive console. It also mounts /var/run/docker.sock; retain that mount only on a trusted host where the control plane is allowed to create local containers.

If a trusted browser client must call this server directly, set AKOFLOW_API_ALLOWED_ORIGINS to the exact comma-separated HTTPS origins and add that variable to the server service. The server only accepts origins that match the list exactly; it has no wildcard origin mode. Prefer an SSH tunnel or a reverse proxy when this is not necessary.

4. Start and verify

Start the two services using the local images:

docker compose -f compose.yaml up -d
docker compose -f compose.yaml ps
docker compose -f compose.yaml logs --tail=100 akoflow-server

The server's public preflight endpoint reports the server and local dependency state without exposing operational data:

curl --fail-with-body --silent http://127.0.0.1:8080/akoflow-api/preflight/ | jq .

Check that server.available is true. Then prove that the bearer token is accepted for an operational request:

read -r -s -p "AkôFlow API token: " AKOFLOW_API_TOKEN
printf '\n'
curl --fail-with-body --silent \
-H "Authorization: Bearer ${AKOFLOW_API_TOKEN}" \
http://127.0.0.1:8080/akoflow-api/environments/ | jq .
unset AKOFLOW_API_TOKEN

An empty JSON list is a valid new-instance result. A 401 Unauthorized means the token in the request differs from .env; correct the file and restart the server with docker compose -f compose.yaml up -d.

For an operator working from another machine, use a tunnel rather than exposing the API port:

ssh -N -L 8080:127.0.0.1:8080 <operator>@<instance-host>

Run the same curl commands against your local 127.0.0.1:8080 while the tunnel is open. Continue with the API overview or register infrastructure and execute the first simulated workflow.

Operate, update, and remove

Use the exact same steps with a newer release tag to update: download and verify its archives, load its versioned images, change only AKOFLOW_RELEASE_TAG in .env, then run docker compose -f compose.yaml up -d. The named volumes remain attached, so plans, runs, artifacts, and managed credentials are retained. Export the instance before changing versions if you need an additional recovery point; see Instance management.

To stop the services while retaining their state:

docker compose -f compose.yaml down

Do not add --volumes unless you intend to irreversibly remove the AkôFlow database, artifacts, managed credentials, and BuildKit cache. To inspect the local volumes before any destructive action, run docker volume ls | grep akoflow.

Troubleshooting

SymptomCheck and recovery
manifest unknown or Compose tries to pull an imageVerify AKOFLOW_RELEASE_TAG in .env and repeat docker image load; docker image inspect akoflow/daemon:<tag> must succeed before starting Compose.
Preflight reports BuildKit unavailableRun docker compose -f compose.yaml logs buildkitd; the supplied service needs a Docker host that permits privileged containers.
401 Unauthorized from an API routeRe-enter the token from .env. The preflight route is public, but environments, workflows, plans, runs, and credentials require the bearer token.
State disappeared after a restartUse docker compose ... down, not down --volumes. Inspect the akoflow-state volume before recreating or removing it.
A request needs browser CORS accessConfigure only the exact trusted origin in AKOFLOW_API_ALLOWED_ORIGINS; do not use a wildcard or expose the API port directly.

For server logs, Docker/BuildKit diagnostics, and network checks, see Troubleshooting.