Export Ollama models to tar archives or push them directly to OCI-compliant registries. Built for airgapped and private-network environments where you cannot reach the public Ollama registry.
- Pull models from the Ollama registry via the local Ollama daemon
- Export any locally cached model to a self-contained tar archive
- Import a tar archive back into the local Ollama model store
- Push directly to an OCI registry (Harbor, Nexus, Docker Registry v2, …)
- Chunked PATCH uploads — works correctly behind Traefik and other proxies
- Automatic CSRF token handling (Harbor)
- Bearer token + HTTP Basic auth with challenge negotiation
- Blob deduplication (skips blobs already present on the target)
pip install ollama-exportergit clone https://github.com/thenomadbeyond/ollama-export
cd ollama-exporter
pip install -e .Pre-built binaries are available on the Releases page — no Python required.
chmod +x ollama-exporter-linux-amd64
./ollama-exporter-linux-amd64 --help- Python 3.9+
- A running
ollama serveinstance (default:http://localhost:11434)
ollama-exporter list# Public model
ollama-exporter pull llama3.1:8b
# Private registry — inline credentials
ollama-exporter pull registry.example.com/myorg/mymodel:v1 -u alice -p secret
# Private registry — password from stdin (avoids credentials in shell history)
echo "$TOKEN" | ollama-exporter pull registry.example.com/myorg/mymodel:v1 \
-u alice --password-stdin
# Private registry — credentials from environment variables
export OLLAMA_USERNAME=alice
export OLLAMA_PASSWORD=secret
ollama-exporter pull registry.example.com/myorg/mymodel:v1ollama-exporter export mistral:latest mistral-latest.tar
ollama-exporter export llama3.1:8b /mnt/usb/llama3.1-8b.tar# Model name is inferred from the filename
ollama-exporter import mistral-latest.tar
# Override the name/tag on import
ollama-exporter import /mnt/usb/llama3.1-8b.tar --tag llama3.1:8b# Inline credentials
ollama-exporter push mistral:latest registry.example.com/ai/mistral:latest \
-u admin -p secret
# Password from stdin (CI-friendly, nothing in shell history)
echo "$TOKEN" | ollama-exporter push mistral:latest registry.example.com/ai/mistral:latest \
-u admin --password-stdin
# Credentials from environment variables
export OCI_USERNAME=admin
export OCI_PASSWORD=secret
ollama-exporter push mistral:latest registry.example.com/ai/mistral:latest
# Plain HTTP registry (e.g. internal dev)
ollama-exporter push qwen2.5-coder:7b registry.local/ai/qwen2.5-coder:7b \
--insecure
# Tune chunk size if the proxy has tight timeouts (default: 64 MiB)
ollama-exporter push llama3.1:8b registry.example.com/ai/llama3.1:8b \
--chunk-size 16[internet machine]
ollama-exporter pull llama3.1:8b
ollama-exporter export llama3.1:8b llama3.1-8b.tar
# copy tar to USB drive / sftp / object storage
[airgapped machine]
ollama-exporter import llama3.1-8b.tar
# model is immediately available to ollama serve
Or, if your private network has an OCI registry reachable from both sides:
[internet machine]
ollama-exporter pull llama3.1:8b
ollama-exporter push llama3.1:8b registry.internal/ai/llama3.1:8b
[airgapped machine]
ollama pull registry.internal/ai/llama3.1:8b
| Variable | Default | Description |
|---|---|---|
OLLAMA_HOST |
http://localhost:11434 |
Ollama API base URL |
OLLAMA_MODELS |
~/.ollama/models |
Ollama model store path |
OLLAMA_USERNAME |
— | Username for pull from a private registry |
OLLAMA_PASSWORD |
— | Password for pull from a private registry |
OCI_USERNAME |
— | Username for push to an OCI registry |
OCI_PASSWORD |
— | Password for push to an OCI registry |
| Registry | Tested |
|---|---|
| Harbor | Yes |
| Docker Registry v2 | Yes |
| Nexus OSS | Should work |
| Gitea / Forgejo | Should work |
| AWS ECR | Untested |
| GHCR | Untested |
Ollama stores models on disk in OCI format:
~/.ollama/models/
├── manifests/registry.ollama.ai/library/<name>/<tag> # OCI manifest JSON
└── blobs/sha256-<hash> # binary blobs
ollama-exporter reads these files directly — no re-downloading from the internet. A tar export packages the manifest and all referenced blobs. An OCI push uploads each blob via the OCI Distribution Spec v2 API and then uploads the manifest.
See SECURITY.md.