Arango logo

Install the data platform on-premises offline

How to set up the Contextual Data Platform on your own hardware in an environment without internet access, including air-gapped environments

For offline installation and the special case of a fully air-gapped environment, you need another environment with internet access to download data and for generating license keys. Data needs to be transferred in both directions between the offline and the online environment at different steps, but mainly from the online to offline system and only small amounts from the offline to the online system (for the licensing).

What needs to be done in which environment is indicated by each step:

  • Air-gapped system: The offline environment.
  • Internet-connected system: The online environment.

Step 1: Download the installation files and information

Internet-connected system

In case of an installation on hardware without internet access, everything needed to install the services of the data platform has to be downloaded on a system with internet access and needs to be transferred to the offline or air-gapped system before the setup.

  • You receive license credentials from the Arango team. Store them securely on the system with internet access for repeated use.

    The license credentials are composed of a client ID and client secret that you need to activate a deployment online or to generate license keys for offline deployments (e.g. air-gapped).

  • You either receive a package configuration file or a pre-made package for download.

    A platform package is a zipped file that contains manifests and container images of various services for installing the Contextual Data Platform. You can import the platform package into your container registry from where Kubernetes can pull the images.

    A Contextual Data Platform package configuration is a YAML file that defines which services to install and their configurations. You can use it to create a platform package yourself by exporting from Arango’s container registry.

  • Download the latest enterprise version of the ArangoDB Kubernetes Operator kube-arangodb from https://github.com/arangodb/kube-arangodb/releases .

    Look for the file called kube-arangodb-enterprise-x.x.x.tgz (where x.x.x is the version number). It is the operator for x86-64 CPUs. You may need to click Show all # assets to reveal all files.

  • Download the Arango Contextual Data Platform CLI tool arangodb_operator_platform from https://github.com/arangodb/kube-arangodb/releases . It is available for Linux, macOS, and Windows for the x86-64 as well as 64-bit ARM architecture, for example:

    • arangodb_operator_platform_darwin_arm64 for macOS with Apple M1 and later CPUs
    • arangodb_operator_platform_linux_amd64 for Linux-based systems with x86-64 CPU
    • arangodb_operator_platform_linux_arm64 for Linux-based systems with 64-bit ARM CPU
    • arangodb_operator_platform_windows_amd64 for Windows with 64-bit x86-64 CPU

    The Platform CLI tool simplifies the further setup and later management of the Platform’s Kubernetes services. You also need it on the system with internet access for generating license keys.

    It is recommended to rename the downloaded executable to arangodb_operator_platform (with an .exe extension on Windows) and add it to the PATH environment variable to make it available as a command in the system.

    On Linux and macOS, you need to make the file executable. Your file manager may allow that in a visual way, or you can use a command-line to run chmod +x arangodb_operator_platform.

    On macOS, you may additionally need to run xattr -r -d com.apple.quarantine arangodb_operator_platform in a command-line to remove the flag that marks it as downloaded from the internet to be able to run it.

  • Pull the necessary images from the internet and save them to files in order to copy them to the air-gapped system.

    You can use container management tool like Docker but you can also use a dedicated tool like regctl instead. Keep in mind that you also need this tool in the air-gapped environment to load the images into the container registry.

    You need at least the image of the ArangoDB Kubernetes Operator (arangodb/kube-arangodb-enterprise). If you want to use a local MinIO instance for blob storage, make sure to also get this image (e.g. minio/minio:latest). The process is the same for any image.

    docker pull docker.io/arangodb/kube-arangodb-enterprise:1.4.2
    docker save docker.io/arangodb/kube-arangodb-enterprise:1.4.2 -o kube-arangodb-enterprise.tar
    

    Download the regctl executables that match your systems from https://github.com/regclient/regclient/releases/ .

    In the following, the assumed name of the executable is regctl.

    On Linux and macOS, you need to make the file executable. Your file manager may allow that in a visual way, or you can use a command-line to run chmod +x regctl.

    On macOS, you may additionally need to run xattr -r -d com.apple.quarantine regctl in a command-line to remove the flag that marks it as downloaded from the internet to be able to run it.

    To pull the image and save it to a file as follows:

    regctl image export docker.io/arangodb/kube-arangodb-enterprise:1.4.2 kube-arangodb-enterprise.tar
    

Step 2: Import the images

Air-gapped system

You need to import at least the image of the ArangoDB Kubernetes Operator into your local container registry. The operator can then pull this and any other image you may need from there without internet access.

docker load -i kube-arangodb-enterprise.tar

docker tag arangodb/kube-arangodb-enterprise:1.4.2 \
  <YOUR_REGISTRY_ADDRESS:5000>/arangodb/kube-arangodb-enterprise:1.4.2

docker push <YOUR_REGISTRY_ADDRESS:5000>/arangodb/kube-arangodb-enterprise:1.4.2

The --host parameter is only needed if your container registry uses HTTP as opposed to HTTPS:

regctl image import \
  <YOUR_REGISTRY_ADDRESS:5000>/arangodb/kube-arangodb-enterprise:1.4.2 \
  kube-arangodb-enterprise.tar \
  --host "reg=<YOUR_REGISTRY_ADDRESS:5000>,tls=disabled"

Step 3: Create a namespace

Air-gapped system

Ensure kubectl is properly configured and can communicate with your Kubernetes cluster, e.g. by running the following commands:

kubectl cluster-info
kubectl get nodes

Create a Kubernetes namespace for ArangoDB and the data platform resources. The namespace used throughout this guide is called arango, but you can use a different name.

kubectl create namespace arango

When you specify the namespace for a command, you can do that in two ways:

  • --namespace arango (long-form option)
  • -n arango (short-form option)

This guide uses long-form options for clarity.

Step 4: Install the Operator

Air-gapped system

Install the ArangoDB Kubernetes Operator  (kube-arangodb) from the downloaded .tgz file with Helm.

This operator is the core component that manages ArangoDB deployments and the Contextual Data Platform. It watches for custom resources and creates the necessary Kubernetes resources.

Make sure to set the options as shown below to enable the gateway feature and machine learning feature:

VERSION_OPERATOR='1.4.2' # Use a newer version if available

helm upgrade --install operator \
  --namespace arango \
  "kube-arangodb-enterprise-${VERSION_OPERATOR}.tgz" \
  --set "webhooks.enabled=true" \
  --set "operator.args[0]=--deployment.feature.gateway=true" \
  --set "operator.architectures={amd64}"

The output looks similar to the following on success:

Release "operator" does not exist. Installing it now.
NAME: operator
LAST DEPLOYED: Thu Feb  5 16:12:21 2026
NAMESPACE: arango
STATUS: deployed
REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None
NOTES:
You have installed Kubernetes ArangoDB Operator in version 1.4.2

To access ArangoDeployments you can use:

kubectl --namespace "arango" get arangodeployments

More details can be found on https://github.com/arangodb/kube-arangodb/tree/1.4.2/docs

You may use the following commands to wait for the operator to be ready and verify it is running:

kubectl wait --for=condition=ready pod --selector app.kubernetes.io/name=kube-arangodb-enterprise --namespace arango --timeout=120s

kubectl get deployment --namespace arango --selector app.kubernetes.io/name=kube-arangodb-enterprise
kubectl get pods --namespace arango --selector app.kubernetes.io/name=kube-arangodb-enterprise

Expected output (x stands for varying letter or digit):

pod/arango-operator-operator-xxxxxxxxxx-xxxxx condition met

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
arango-operator-operator   1/1     1            1           45s

NAME                                        READY   STATUS    RESTARTS   AGE
arango-operator-operator-xxxxxxxxxx-xxxxx   2/2     Running   0          45s

Step 5: Create a deployment

Air-gapped system

Create an ArangoDeployment specification for ArangoDB. See the ArangoDeployment Custom Resource Overview  and the linked reference. The example below is a minimal specification

You need to enable the gateway feature by setting spec.gateway.enabled and spec.gateway.dynamic to true in the specification. Enable vector indexes (on DB-Servers and Coordinators respectively on single server) because they are required by features such as GraphRAG. You also need to set spec.license to a secret that you will create later.

Example for an ArangoDB cluster deployment using version 3.12.9 with three DB-Servers and two Coordinators with the name deployment-example:

apiVersion: "database.arangodb.com/v1"
kind: "ArangoDeployment"
metadata:
  name: "deployment-example"
spec:
  mode: Cluster
  image: "arangodb/enterprise:3.12.9"
  gateway:
    enabled: true
    dynamic: true
  gateways:
    count: 1
  dbservers:
    count: 3
    args:
      - --vector-index  # For ArangoDB versions before 4.0.0
  coordinators:
    count: 2
    args:
      - --vector-index  # For ArangoDB versions before 4.0.0
  license:
    secretName: arango-license-key
  # ...

You can save the specification as a YAML file, e.g. deployment.yaml.

Apply the specification using the previously created name (here: arango) and wait for the pods to be ready:

kubectl apply --namespace arango -f deployment.yaml

kubectl get pods --namespace arango --watch  # Ctrl+C to stop watching

Given the above specification using the name deployment-example, you should eventually see pods with the following names with a status of Running:

  • deployment-example-agnt-* (3 Agents)
  • deployment-example-crdn-* (2 Coordinators)
  • deployment-example-prmr-* (3 DB-Servers)
  • deployment-example-gway-* (1 Gateway)

Step 6: Collect information for the licensing

Air-gapped system

Before you can create a license key that you can apply on the air-gapped system, you need to get some information about the ArangoDB deployment. For an overview of how licensing works end-to-end in Kubernetes-managed deployments, including air-gapped environments, see License Management.

Use the Platform CLI tool to create an inventory file. You need to specify the authentication method for ArangoDB (Disabled, Basic, Token), additional authentication details depending on the selected authentication method, where the ArangoDB instance can be reached, as well as a file path for the inventory file:

arangodb_operator_platform license inventory \
  --arango.authentication <auth-method> \
  ... # See below
  --arango.endpoint <arangodb-endpoint> \
  inventory.json

The required authentication options per authentication method:

  • Disabled:
    If the ArangoDB instance has authentication disabled, then you don’t need to specify any additional authentication details. You can also leave out --arango.authentication Disabled because Disabled is the default value.

  • Basic:
    If you want to use ArangoDB user credentials, you need to specify that you want to use HTTP Basic Authentication together with a user name and their password:

      --arango.authentication Basic \
      --arango.basic.username "<user-name>" \
      --arango.basic.password "<password>" \
    
  • Token:
    If you want to use a JWT session token, you need to specify that you want to use a token as well as the JWT itself:

      --arango.authentication Token \
      --arango.token <jwt> \
    

If the ArangoDB instance uses a self-signed certificate, you need to specify the following additional option to skip TLS certificate validation:

  --arango.insecure \

Full command example:

arangodb_operator_platform license inventory \
  --arango.authentication Basic \
  --arango.basic.username root \
  --arango.basic.password "" \
  --arango.insecure \
  --arango.endpoint https://127.0.0.1:8529 \
  inventory.json

Expected output:

2026-02-05T17:03:07+01:00 INF Connecting to the server...
2026-02-05T17:03:07+01:00 INF Discovered Arango 3.12.9 (enterprise)
2026-02-05T17:03:07+01:00 INF Starting executor name=server.mode thread=0
2026-02-05T17:03:07+01:00 INF Starting executor name=server.info thread=0
2026-02-05T17:03:07+01:00 INF Starting executor name=aql.timestamp thread=0
2026-02-05T17:03:07+01:00 INF Starting executor name=deployment.id thread=0

Finally, get the deployment ID using an endpoint of ArangoDB’s HTTP API. Substitute https://127.0.0.1:8529 with the endpoint at which ArangoDB can be reached. You may need to specify additional options for authentication in place of ...:

curl ... https://127.0.0.1:8529/_admin/deployment/id

The authentication options:

  • Disabled:
    If the ArangoDB instance has authentication disabled, then you don’t need to specify any additional authentication options.

  • Username and password:
    If you want to use ArangoDB user credentials, set cURL’s -u option and provide the user name and password separated by a colon:

    curl -u "<user-name>:<password>" https://...
    
  • Token:
    If you want to use a JWT session token, use cURL’s -H option to set an HTTP header with the token:

    curl -H "Authorization: bearer <token>" https://...
    

If the ArangoDB instance uses self-signed certificates, you additionally need to set the --insecure / -k option to skip TLS certificate validation:

curl --insecure ...

Full command example:

curl -u "root:" --insecure https://127.0.0.1:8529/_admin/deployment/id

Expected output (x stands for varying letter or digit):

{"id":"xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx"}

The UUID wrapped in quote marks is the deployment ID.

Step 7: Generate a license key

Internet-connected system

Use your license credentials together with the inventory file and deployment ID from the previous step to obtain a license key. You can do this with the License Activation portal or with the Platform CLI tool — both produce an equivalent license key.

  1. Open https://activate.license.arango.ai/  in a browser.
  2. Enter your License Client ID and License Client Secret.
  3. Choose how to identify the deployment:
    • Inventory (default): drop the inventory.json file into the upload area, or click to select it. Captures the full deployment shape and is recommended for air-gapped deployments.
    • Managed — Deployment ID only: enter the deployment ID from the previous step. No inventory file is needed. Available only if Managed activation is enabled for your license — check your contract or with your Arango contact. If it is not enabled, use Inventory mode instead.
  4. Optionally enable Custom TTL to override the default license duration. Accepts values like 24h, 168h, 7d, or 3600s.
  5. Click Activate and copy the generated license key (e.g. into a local license.txt file). You will use it in the next step to create the Kubernetes secret on the air-gapped system.

The activation portal is a convenient alternative for users who would otherwise run arangodb_operator_platform license generate. Inventory mode still requires the Platform CLI tool to produce inventory.json in the previous step; Managed mode skips that step entirely.

Substitute <license-client-id> and <license-client-secret> with the actual license credentials. Specify the path to the inventory file inventory.json and replace <deployment-id> with the deployment ID from the previous step.

arangodb_operator_platform license generate \
  --license.client.id <license-client-id> \
  --license.client.secret <license-client-secret> \
  --inventory ./inventory.json \
  --deployment.id <deployment-id>

The command logs information to the standard output (also known as stdout) and writes the license key to the standard error stream (also known as stderr). You may want to redirect stderr and thus the license key to a file by appending 2> license.txt to the above command (with a leading space).

You can also set the license credentials as environment variables LICENSE_CLIENT_ID and LICENSE_CLIENT_SECRET. You can then leave out the --license.client.id and --license.client.secret command-line options.

export LICENSE_CLIENT_ID=<license-client-id>
export LICENSE_CLIENT_SECRET=<license-client-secret>

arangodb_operator_platform license generate \
  --inventory ./inventory.json \
  --deployment.id <deployment-id>

Expected output (stdout, x stands for varying letter or digit):

2026-02-05T17:27:28+01:00 INF Using identity for client identity={}
2026-02-05T17:27:28+01:00 INF Generating License ClusterID=<deployment-id> Inventory=true
2026-02-05T17:27:28+01:00 INF License Generated and printed to STDERR ClusterID=<deployment-id> Inventory=true LicenseID=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Step 8: Create a secret for the license

Create a Kubernetes secret with your license credentials.

Substitute <license-string> with the license key you generated:

kubectl create secret generic arango-license-key \
  --namespace arango \
  --from-literal=token-v2="<license-string>"

You may run the following command to verify that the secret was created:

kubectl get secret arango-license-key --namespace arango

Expected output:

NAME                 TYPE     DATA   AGE
arango-license-key   Opaque   2      10s

Step 9: Create a Contextual Data Platform package

Internet-connected system

If the Arango team provided you a pre-made platform package, download it and continue with the next step. Otherwise, create a platform package yourself as described below.

Use the Platform CLI tool to download the manifests and container images of the data platform from Arango’s public container registry. This requires license credentials and internet access to *.license.arango.ai.

What to download is defined by the package configuration file that you received from the Arango team. The Platform CLI tool creates a single .zip file out of the downloaded data. Depending on the configuration, it can be over 40 GiB.

Substitute <license-client-id> and <license-client-secret> with the actual license credentials and ./platform.yaml with the path to the package configuration file. Specify the path and a file name for the output file, e.g. platform.zip:

arangodb_operator_platform package export \
  --license.client.id "<license-client-id>" \
  --license.client.secret "<license-client-secret>" \
  ./platform.yaml \
  platform.zip

It can take a while to download everything. If you get errors because of internet connection issues or timeouts, re-run the command. The Platform CLI tool caches what it downloads in a cache folder in the current working directory. You can therefore retry and continue the download where it left off.

Step 10: Import the Contextual Data Platform package

Load the manifests and container images stored in the zipped package into your container registry using the Platform CLI tool.

Specify the address under which the container registry is available and the path to the platform.zip file. Furthermore, provide a file path for the Platform CLI tool to write the package configuration to. This file will be used in the next step:

arangodb_operator_platform package import \
  <YOUR_REGISTRY_ADDRESS:5000> \
  ./platform.zip \
  platform.imported.yaml

If the container registry uses the HTTP protocol instead of HTTPS, you need to specify the following option in addition:

  --registry.docker.insecure <YOUR_REGISTRY_ADDRESS:5000>

Step 11: Install the Contextual Data Platform package

Air-gapped system

Install the platform package using the Platform CLI tool.

The package installation creates and enables various services, including the unified web interface of the Contextual Data Platform.

The platform name (deployment-example) needs to match the name as specified in the ArangoDeployment configuration. Substitute ./platform.imported.yaml with the path to the package configuration file from the previous step:

arangodb_operator_platform --namespace arango package install \
  --platform.name deployment-example \
  ./platform.imported.yaml

It can take a while to import everything into the container registry.

Step 12: Set up object storage

Air-gapped system

Features like MLflow and GraphML require an additional storage system to save model training data, for instance.

The following example shows how to set up a local MinIO and integrate it with the Arango Contextual Data Platform, but you can also use a remote object storage like S3. For the supported storage systems, see the kube-arangodb documentation .

Create a Kubernetes namespace for MinIO, then create a secret in this namespace with the username and password to use for the MinIO root user (replace minioadmin and miniopassword with the credentials you actually want to use). Create another secret with the same credentials but in the namespace of your ArangoDeployment, which is arango in this example:

kubectl create namespace minio

kubectl create secret generic minio-root \
  --namespace minio \
  --from-literal=MINIO_ROOT_USER=minioadmin \
  --from-literal=MINIO_ROOT_PASSWORD=miniopassword

kubectl create secret generic minio-credentials \
  --namespace arango \
  --from-literal=accessKey=minioadmin \
  --from-literal=secretKey=miniopassword

Create a file to configure MinIO service and call it e.g. minio.yaml. Example using a Persistent Volume Claim (PVC) of five gibibytes:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: minio-data-pvc
 namespace: minio
spec:
 accessModes:
   - ReadWriteOnce
 resources:
   requests:
     storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: minio
  namespace: minio
spec:
  replicas: 1
  selector:
    matchLabels:
      app: minio
  template:
    metadata:
      labels:
        app: minio
    spec:
      containers:
      - name: minio
        image: minio/minio:latest
        args:
          - server
          - /data
        envFrom:
          - secretRef:
              name: minio-root
        ports:
          - containerPort: 9000
        volumeMounts:
          - name: data
            mountPath: /data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: minio-data-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: minio
  namespace: minio
spec:
  selector:
    app: minio
  ports:
    - port: 9000
      targetPort: 9000
---
apiVersion: batch/v1
kind: Job
metadata:
  name: minio-create-bucket
  namespace: minio
spec:
  backoffLimit: 1
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: mc
          image: minio/mc
          env:
            - name: MINIO_ENDPOINT
              value: http://minio.minio.svc.cluster.local:9000
            - name: MINIO_ACCESS_KEY
              valueFrom:
                secretKeyRef:
                  name: minio-root
                  key: MINIO_ROOT_USER
            - name: MINIO_SECRET_KEY
              valueFrom:
                secretKeyRef:
                  name: minio-root
                  key: MINIO_ROOT_PASSWORD
          command:
            - sh
            - -c
            - |
              mc alias set local $MINIO_ENDPOINT $MINIO_ACCESS_KEY $MINIO_SECRET_KEY
              mc mb local/arango-platform-storage || true

Set up the MinIO service by applying the configuration file:

kubectl apply -f ./minio.yaml

Create another file to configure the storage for the Contextual Data Platform and call the file e.g. platform-storage.yaml. Note that the name of the ArangoPlatformStorage must be the same as for the ArangoDeployment:

apiVersion: platform.arangodb.com/v1beta1
kind: ArangoPlatformStorage
metadata:
  name: deployment-example
  namespace: arango
spec:
  backend:
    s3:
      bucketName: arango-platform-storage
      credentialsSecret:
        name: minio-credentials
      endpoint: http://minio.minio.svc.cluster.local:9000

Integrate the object storage with the Contextual Data Platform by applying the file:

kubectl apply -f ./platform-storage.yaml