Offline (Air-Gapped) Installation of MOJO¶
This guide covers installing and running the MOJO Platform on a Linux server that has no outbound internet access. Every artifact that the standard installer would download at runtime is instead prepared on an internet-connected staging machine and transferred to the target host via USB drive, SCP, or other secure media.
Metify Support Required
An offline installation requires coordination with Metify. Before you begin, contact support@metify.io to obtain:
- Your MOJO License Key
- Your encrypted license string (the
MOJO_LICENSEvalue) - Repository credentials (
MOJO_REPOSITORY_USERNAMEandMOJO_REPOSITORY_PASSWORD)
In a standard online installation these values are fetched automatically from the license server. In an offline installation you must receive them ahead of time and configure them manually.
Overview¶
A standard MOJO installation contacts the internet at four points:
| Step | What is downloaded | Script |
|---|---|---|
| 1 | System packages (curl, jq, etc.) | mojo-install |
| 2 | mojo-setup.tgz installer archive |
mojo-install |
| 3 | License + repository credentials from licenses.metify.io |
mojo-setup |
| 4 | Container images from download.metify.io |
mojo-launcher |
An offline installation replaces each step with a local equivalent. The sections below walk through preparing and executing each one.
System Requirements¶
The target (air-gapped) host must meet the same requirements as an online installation:
| Resource | Requirement |
|---|---|
| OS | Ubuntu 22.04/24.04, Debian 12/13, RHEL 9/10, Rocky Linux, Alma Linux |
| Memory | Minimum 16 GB RAM |
| Disk Space | At least 80 GB free (more if storing OS/firmware bundles) |
| Container Runtime | Docker or Podman pre-installed |
Container Runtime
The air-gapped host must already have Docker or Podman installed. The MOJO installer can install Docker automatically, but that process requires internet access. Install your container runtime from local packages or your organization's internal package repository before proceeding.
Phase 1 -- Prepare Artifacts (Internet-Connected Machine)¶
Perform the following steps on a staging machine that has internet access. All artifacts will be transferred to the air-gapped target later.
1.1 Download the Installer Archive¶
Download the mojo-setup.tgz archive and the mojo-install bootstrap script:
mkdir -p ~/mojo-offline && cd ~/mojo-offline
# Download the latest stable installer archive
curl -fLO https://download.metify.io/repository/filestore-external/mojo-installer/releases/latest/mojo-setup.tgz
# Download the bootstrap script (optional -- included in the archive)
curl -fLO https://download.metify.io/repository/filestore-external/mojo-installer/releases/latest/mojo-install
1.2 Download the System Dependency Packages¶
On the staging machine (or a machine running the same OS and version as the target), download the required packages for offline installation.
Note
Use --resolve (dnf) or download dependencies explicitly to ensure all transitive dependencies are included. The target machine may not have anything beyond a minimal OS installation.
1.3 Pull and Export Container Images¶
Log in to the MOJO repository and pull all required images. Then export them as tar archives.
# Authenticate with the MOJO repository
# Use the credentials provided by Metify support
docker login https://download.metify.io -u <MOJO_REPOSITORY_USERNAME>
# Pull all MOJO platform images
docker pull download.metify.io/mojo/coordinator:latest
docker pull download.metify.io/mojo/yoda-gui:latest
docker pull download.metify.io/mojo/postgres:16.3
docker pull download.metify.io/mojo/redis:7.2.4
docker pull download.metify.io/mojo/redfish-mock:latest
docker pull download.metify.io/mojo/consoler:1.0
docker pull download.metify.io/mojo/tor/grub-builder:1.0
docker pull download.metify.io/mojo/tor/ipxe-builder:c1834f-1.0
docker pull download.metify.io/mojo/tor/traefik:3.6.7
docker pull download.metify.io/mojo/tor/nginx:1.25.3
docker pull download.metify.io/mojo/tor/dhcpd:1.0
docker pull download.metify.io/mojo/tor/tftpd:1.0
docker pull download.metify.io/mojo/tor/pxe-helper:1.0
# Export all images into a single tar archive
docker save \
download.metify.io/mojo/coordinator:latest \
download.metify.io/mojo/yoda-gui:latest \
download.metify.io/mojo/postgres:16.3 \
download.metify.io/mojo/redis:7.2.4 \
download.metify.io/mojo/redfish-mock:latest \
download.metify.io/mojo/consoler:1.0 \
download.metify.io/mojo/tor/grub-builder:1.0 \
download.metify.io/mojo/tor/ipxe-builder:c1834f-1.0 \
download.metify.io/mojo/tor/traefik:3.6.7 \
download.metify.io/mojo/tor/nginx:1.25.3 \
download.metify.io/mojo/tor/dhcpd:1.0 \
download.metify.io/mojo/tor/tftpd:1.0 \
download.metify.io/mojo/tor/pxe-helper:1.0 \
-o ~/mojo-offline/mojo-images.tar
Compression
The image archive can be 5-10 GB. Compress it to speed up transfer:
Podman
If the staging machine uses Podman instead of Docker, replace docker with podman in the commands above. The exported tar format is compatible between Docker and Podman.
1.4 (Optional) Download OS and Firmware Bundles¶
If you plan to provision servers with MOJO, download the OS bundles and firmware bundles you need:
# OS Bundle example (Ubuntu 22.04)
curl -fL -o ~/mojo-offline/ubuntu-22.04.03-x86_64.tar.gz \
--user "<MOJO_REPOSITORY_USERNAME>:<MOJO_REPOSITORY_PASSWORD>" \
"https://download.metify.io/repository/osimages-external/images/ubuntu/22.04.03/x86_64/ubuntu-22.04.03-x86_64.tar.gz"
# MojoLive bundle (required for disk sanitization features)
curl -fL -o ~/mojo-offline/mojolive-1.0.0-x86_64.tar.gz \
--user "<MOJO_REPOSITORY_USERNAME>:<MOJO_REPOSITORY_PASSWORD>" \
"https://download.metify.io/repository/osimages-external/images/mojolive/1.0.0/x86_64/mojolive-1.0.0-x86_64.tar.gz"
1.5 Package Everything for Transfer¶
ls ~/mojo-offline/
# Expected contents:
# mojo-install (bootstrap script)
# mojo-setup.tgz (installer archive)
# mojo-images.tar.gz (container images)
# packages/ (system dependency packages)
# ubuntu-22.04.03-x86_64.tar.gz (optional OS bundle)
# mojolive-1.0.0-x86_64.tar.gz (optional MojoLive bundle)
Transfer the ~/mojo-offline/ directory to the air-gapped target machine using USB drive, SCP over a private network, or any approved file transfer method.
Phase 2 -- Install on the Air-Gapped Target¶
All steps below are performed on the target machine that has no internet access. Assume the offline artifacts have been placed at /tmp/mojo-offline/.
2.1 Install System Dependencies¶
2.2 Extract the Installer¶
# Create the installation directory
sudo mkdir -p /opt/mojo
# Extract the setup archive
sudo tar xzf /tmp/mojo-offline/mojo-setup.tgz -C /opt/mojo
cd /opt/mojo
2.3 Load Container Images¶
Load the exported container images into the local container runtime:
After loading, tag each image with the local/mojo-* tags that MOJO expects. This mirrors what mojo-launcher does during an online pull_images:
# Set RUNTIME to your container command (docker or podman)
RUNTIME=docker # or: RUNTIME=podman
sudo $RUNTIME tag download.metify.io/mojo/tor/traefik:3.6.7 local/mojo-proxy:latest
sudo $RUNTIME tag download.metify.io/mojo/tor/dhcpd:1.0 local/mojo-dhcpd:latest
sudo $RUNTIME tag download.metify.io/mojo/tor/tftpd:1.0 local/mojo-tftpd:latest
sudo $RUNTIME tag download.metify.io/mojo/tor/nginx:1.25.3 local/mojo-static-server:latest
sudo $RUNTIME tag download.metify.io/mojo/tor/pxe-helper:1.0 local/mojo-pxe-helper:latest
sudo $RUNTIME tag download.metify.io/mojo/tor/ipxe-builder:c1834f-1.0 local/mojo-ipxe-builder:latest
sudo $RUNTIME tag download.metify.io/mojo/tor/grub-builder:1.0 local/mojo-grub-builder:latest
sudo $RUNTIME tag download.metify.io/mojo/postgres:16.3 local/mojo-db:latest
sudo $RUNTIME tag download.metify.io/mojo/redis:7.2.4 local/mojo-redis:latest
sudo $RUNTIME tag download.metify.io/mojo/consoler:1.0 local/mojo-consoler:latest
sudo $RUNTIME tag download.metify.io/mojo/coordinator:latest local/mojo-coordinator:latest
sudo $RUNTIME tag download.metify.io/mojo/yoda-gui:latest local/mojo-gui:latest
sudo $RUNTIME tag download.metify.io/mojo/redfish-mock:latest local/mojo-mock:latest
Verify the images are loaded:
You should see all 13 images tagged as local/mojo-*:latest.
2.4 Run Setup (Skip Connection Check)¶
Run mojo-setup with the --skip-connection-check flag since the host cannot reach external servers:
The setup wizard will prompt you for configuration values interactively. Key differences from an online install:
Telemetry¶
When prompted to disable telemetry, answer y (yes, disable):
Since the host has no internet access, telemetry data cannot be sent. Disabling it avoids silent curl timeouts during setup and launcher operations.
License Key and License Server¶
When prompted for your license key, enter the key provided by Metify support:
When prompted for the license server, keep the default. The setup will attempt to contact licenses.metify.io and fail, which is expected. You will see a warning:
This warning is not fatal. The setup will continue. You will manually configure the license in the next step.
Network Configuration¶
Configure your network settings (interface, hostname, IP, netmask, gateway, DNS, DHCP) as you would in a standard installation. These settings apply to your local network and do not require internet access.
2.5 Configure License and Repository Credentials Manually¶
After mojo-setup completes, manually edit configs/mojo.env to add the values that would normally be fetched from the license server:
Set the following values (provided by Metify support):
MOJO_LICENSE_KEY="<your-license-key>"
MOJO_LICENSE="<your-encrypted-license-string>"
MOJO_REPOSITORY_URL="https://download.metify.io"
MOJO_REPOSITORY_USERNAME="<your-repo-username>"
MOJO_REPOSITORY_PASSWORD="<your-repo-password>"
MOJO_TELEMETRY_DISABLE="true"
MOJO_LICENSE vs MOJO_LICENSE_KEY
These are two different values. MOJO_LICENSE_KEY is the API key used to authenticate with the license server. MOJO_LICENSE is the actual encrypted license string that the platform validates at runtime. Both must be set for offline installations. Contact support@metify.io to obtain your MOJO_LICENSE value.
2.6 Start MOJO (Without Pulling Images)¶
Since the images are already loaded locally, start MOJO without the --update flag:
Do Not Use --update
The --update flag triggers pull_images() which attempts to docker login and pull images from download.metify.io. On an air-gapped host this will fail. Always use start mojo without --update for offline installations.
The launcher will:
- Verify the license agreement
- Check container runtime prerequisites
- Render configuration templates
- Start all MOJO services via Docker/Podman Compose
Once complete, you should see:
*********************************************
Mojo Platform started successfully!
https://<your-configured-hostname>
*********************************************
2.7 Access the Web Console¶
Open a browser and navigate to:
Default login credentials:
- Username:
admin - Password:
admin
Change Default Password
Change the default password immediately after your first login.
Phase 3 -- Load OS and Firmware Bundles (Optional)¶
If you downloaded OS bundles or firmware bundles during Phase 1, load them now. MOJO must be running before loading bundles.
Load an OS Bundle from a Local File¶
When prompted Do you have a local os bundle file?, answer y and provide the path:
Do you have a local os bundle file? [yn]: y
Filepath? []: /tmp/mojo-offline/ubuntu-22.04.03-x86_64.tar.gz
Load MojoLive¶
Do you have a local os bundle file? [yn]: y
Filepath? []: /tmp/mojo-offline/mojolive-1.0.0-x86_64.tar.gz
Load a Firmware Bundle from a Local File¶
When prompted Do you have a local firmware bundle file?, answer y and provide the path.
Updating an Offline Installation¶
To update MOJO on an air-gapped host, repeat the artifact preparation process on an internet-connected staging machine:
- Download the new
mojo-setup.tgzfromdownload.metify.io - Pull the latest container images and export them with
docker save - Transfer both to the air-gapped host
Then on the target:
# Stop MOJO
cd /opt/mojo
sudo ./mojo-launcher stop mojo
# Extract the updated installer (preserves configs/ and volumes/)
sudo tar xzf /tmp/mojo-offline/mojo-setup.tgz -C /opt/mojo
# Load updated container images
gunzip -c /tmp/mojo-offline/mojo-images.tar.gz | sudo docker load
# Re-tag all images (same commands as Phase 2, Step 2.3)
# ...
# Re-run setup to pick up any new configuration options
sudo ./mojo-setup --skip-connection-check
# Start MOJO
sudo ./mojo-launcher start mojo
Configuration Preservation
The mojo-setup command detects an existing configs/mojo.env and enters reconfiguration mode. It backs up your current configuration before applying changes, so your network settings, license, and other customizations are preserved.
Troubleshooting¶
"Cannot connect to the docker engine"¶
Ensure Docker or Podman is installed and running before starting MOJO:
Images not found or services fail to start¶
Verify that all local tags exist:
If any are missing, re-run the docker load and docker tag commands from Phase 2, Step 2.3.
License errors at runtime¶
Confirm that both MOJO_LICENSE_KEY and MOJO_LICENSE are set in configs/mojo.env. The MOJO_LICENSE value is the encrypted license string, not the API key. Contact support@metify.io if you need this value.
Telemetry timeout warnings¶
If you see slow startup or timeout messages related to telemetry, verify that MOJO_TELEMETRY_DISABLE="true" is set in configs/mojo.env.
Support¶
If you have any questions about offline installations, please contact us at support@metify.io.