Migration of Julia environment to machine without internet access (offline)

Hi everyone,

I’m trying to migrate a existing Julia environment to a machine without access to internet. I’ve been searching in discourse if there is already a mature solution for doing this, however, I have only found some hints of how this could be done, e.g., Offline Installation of Julia Packages and Package Install on Offline Cluster (*perhaps I don’t completely understand the solutions).

I was wondering that if forward to 2025 there is a clear way to do this. And if there is, if someone can help me to figure out what I should be doing to make this process consistent.

At this point, I have read things as of copying entire folders and doing pre-builds. In my case, installation of Julia on the machine is not a problem. My interest is on having all the necessary packages in the machine.

Cheers!

2 Likes

You could clone the required libraries to a removable drive repo and install from there.

thanks for the response! do you mean something like this? Offline development on an air gapped machine

1 Like

I had in mind something simpler, under the assumption that very few people need all 10,000+ packages but rather have a picklist of, say, 100 packages. Try this out in a test environment.

#!/usr/bin/env julia

using Pkg, TOML
import LocalRegistry
import Dates

const PROJECT_NAME = "AirgapProject"
const LOCAL_REGISTRY_NAME = "MyLocalRegistry"
const LOCAL_REGISTRY_PATH = "local_registry"
const PKG_EXPORT_DIR = "compiled_pkgs"
const JULIA_BINARY_SOURCE = "/opt/julia-1.10.2"   # <-- CHANGE THIS TO YOUR INSTALL PATH
const JULIA_BINARY_DEST = "julia"
const BUNDLE_NAME = "julia_airgap_bundle.tar.gz"

# Create and activate the project
println("🔧 Creating and activating project [$PROJECT_NAME]")
mkpath(PROJECT_NAME)
Pkg.activate(PROJECT_NAME)
Pkg.instantiate()

# Add your packages
packages = [
    "DataFrames", "CSV", "Plots", "HTTP", "GeoMakie"
]
println("📦 Adding packages: ", join(packages, ", "))
Pkg.add(packages)
Pkg.precompile()

# Export packages
println("📦 Exporting packages to [$PKG_EXPORT_DIR]")
Pkg.sandbox(; artifacts=false, destination=PKG_EXPORT_DIR)

# Create local registry
if !isdir(LOCAL_REGISTRY_PATH)
    println("🗂️ Creating local registry [$LOCAL_REGISTRY_NAME]")
    LocalRegistry.create_registry(
        LOCAL_REGISTRY_NAME;
        registry_path = LOCAL_REGISTRY_PATH,
        description = "Airgapped Julia registry created on $(Dates.today())"
    )
end

# Register packages
println("🔁 Registering exported packages")
for (root, _, files) in walkdir(PKG_EXPORT_DIR)
    if "Project.toml" in files
        try
            LocalRegistry.register(path=root, registry=LOCAL_REGISTRY_PATH)
            println("✅ Registered $(basename(root))")
        catch e
            @warn "⚠️ Failed to register $(root)" exception = e
        end
    end
end

# Remove default registry and use only local
Pkg.Registry.rm("General"; force=true)
Pkg.Registry.add(Pkg.RegistrySpec(path=LOCAL_REGISTRY_PATH))

# Final instantiate to verify
Pkg.instantiate()
Pkg.precompile()

# Copy Julia binary
println("🚚 Copying Julia binary from [$JULIA_BINARY_SOURCE] to [$JULIA_BINARY_DEST]")
run(`cp -r $JULIA_BINARY_SOURCE $JULIA_BINARY_DEST`)

# Create launch script
launcher = """
#!/bin/bash
DIR=\$(cd \$(dirname \$0) && pwd)
\${DIR}/julia/bin/julia --project=\${DIR}/AirgapProject -e '
    using Pkg
    Pkg.Registry.add(Pkg.RegistrySpec(path=joinpath(@__DIR__, "loca
"""

# then in shell on the airgapped machine
tar -xzf julia_airgap_bundle.tar.gz
./run_airgap.sh

I haven’t tested this, but it should be debuggable to get you to Julia-on-a-stick. If run in a clean environment to a clean device it should be safe from anything after theoretically possible malware packages in the registry. If feeling particularly cautious, use a dedicated device for each system to be installed to, so as not to pass around any germs that may be lurking from other vectors.

2 Likes