Offline / Airgapped Installation
OpenTranscribe supports complete offline deployment for airgapped environments, secure facilities, or locations with limited internet access.
Overview
In offline mode, OpenTranscribe operates without any internet connectivity:
- ✅ Transcription works fully offline
- ✅ Speaker diarization works offline — only if the diarizer's weights were included in the
package you built. Neither engine can provision itself air-gapped: the native
diar-nativesidecar's ONNX/PLDA export and the in-process PyAnnote fork's weights both come from HuggingFace, and an offline machine has no route there. See Including the native diarizer (diar-native) below. - ✅ All AI models cached locally — when fetched with
scripts/download-models.sh. The hand-rolled recipe below omits the NLTK corpora; see the warning there. - ✅ No external API calls
- 💡 Set
NLTK_OFFLINE=1alongsideHF_HUB_OFFLINE=1so a missing corpus fails fast naming the setup step, instead of hanging on a socket timeout. - Not supported: YouTube downloads (requires internet)
- Not supported: Cloud LLM providers (use local LLM instead)
Prerequisites
You'll need an internet-connected machine to:
- Download Docker images
- Download AI models (several GB — see below)
- Prepare installation package
Then transfer everything to your offline machine.
Step 1: Prepare on Internet-Connected Machine
Download Docker Images
# Pull all required images
docker pull davidamacey/opentranscribe-backend:latest
docker pull davidamacey/opentranscribe-frontend:latest
docker pull postgres:17.5-alpine
docker pull redis:8.2.2-alpine3.22
docker pull minio/minio:RELEASE.2025-09-07T16-13-09Z
docker pull opensearchproject/opensearch:3.4.0
# Save images to tarball
docker save -o opentranscribe-images.tar \
davidamacey/opentranscribe-backend:latest \
davidamacey/opentranscribe-frontend:latest \
postgres:17.5-alpine \
redis:8.2.2-alpine3.22 \
minio/minio:RELEASE.2025-09-07T16-13-09Z \
opensearchproject/opensearch:3.4.0
Download AI Models
# Set HuggingFace token
export HUGGINGFACE_TOKEN=hf_your_token_here
# Download models using Python
python3 << 'EOF'
from transformers import WhisperForConditionalGeneration, WhisperProcessor
from pyannote.audio import Model
import torch
# WhisperX models
WhisperForConditionalGeneration.from_pretrained("Systran/faster-whisper-large-v2")
WhisperProcessor.from_pretrained("Systran/faster-whisper-large-v2")
# PyAnnote model (the only repo OpenTranscribe actually gates on)
Model.from_pretrained("pyannote/speaker-diarization-community-1")
EOF
# Package model cache
tar -czf ai-models.tar.gz ~/.cache/huggingface ~/.cache/torch ~/.cache/nltk_data
The Python snippet fetches the transcription and diarization weights and nothing
else. It omits the NLTK corpora, which the sentence splitter and topic
extraction load at runtime — and on an airgapped host those fetches do not fail
fast, because nltk.download swallows its own network errors. The symptoms are
quiet: transcripts chunked by the regex fallback instead of punkt (different
chunk boundaries, therefore different search results), and keyword extraction
keeping common words.
Use scripts/download-models.sh instead, which fetches every group the app
loads, or ./opentr.sh start, which calls it. To fetch just the corpora:
python3 scripts/download-models.py --only nltk
Issue #491 tracked this gap.
Including the native diarizer (diar-native)
The hand-rolled recipe above has the same gap for the native diarization engine
(diar-native, the default local diarizer as of v0.5.0 — see
Speaker Diarization):
it fetches PyAnnote's .bin weights but never runs the ONNX/PLDA export diar-server needs, so
a package built by hand this way ships no diar-native model set at all. That is not fatal —
without it, diarization falls back to the in-process PyAnnote engine — but it means an
air-gapped install with no native sidecar unless you provision one before disconnecting.
The maintained way to build a complete offline package is scripts/build-offline-package.sh
(not the manual docker save/tar steps below, which predate it and remain useful for
understanding what a package contains). It already handles diar-native:
download_models()mounts adiar-nativemodel-cache directory into the backend container and runsscripts/download-models.pywith no filter, which includes thediar-nativegroup — this shells out todiar-server provision-modelswith the sameHUGGINGFACE_TOKENused for every other model, producing the export on the build machine (which has internet access).- The export is copied into the package at
models/diar-native/, anddocker-compose.diar-native.ymlis copied intoconfig/so the offline install can load the sidecar with nothing else to fetch. scripts/opentr-offline.sh(the offline stack's equivalent ofopentr.sh) auto-loads that overlay whenevermodels/diar-native/is non-empty on the target machine — there is no network route for it to checkHUGGINGFACE_TOKENand provision on the fly the way the connected install's lifespan hook does, so a populated export is the only signal it can act on.- If
HUGGINGFACE_TOKENlacks access to pyannote/speaker-diarization-community-1 when you run the build script, it copies nothing and prints a warning rather than failing the whole build — the resulting package still works, just on the PyAnnote fallback instead of the native engine.
Download Installation Files
# Clone repository
git clone https://github.com/attevon-llc/OpenTranscribe.git
cd OpenTranscribe
# Create offline package
tar -czf opentranscribe-offline.tar.gz \
docker-compose.yml \
docker-compose.offline.yml \
.env.example \
database/ \
scripts/ \
opentranscribe.sh
# Copy offline setup script
cp setup-opentranscribe.sh opentranscribe-offline-setup.sh
Step 2: Transfer to Offline Machine
Transfer these files to offline machine:
opentranscribe-images.tar(~8GB)ai-models.tar.gz(several GB; size depends onWHISPER_MODELand how many neural-search models you include)opentranscribe-offline.tar.gz(~5MB)
Via USB drive, secure file transfer, or your organization's approved method.
Step 3: Install on Offline Machine
Load Docker Images
# Load images
docker load -i opentranscribe-images.tar
Extract Installation Files
# Extract installation
tar -xzf opentranscribe-offline.tar.gz
cd opentranscribe
# Extract AI models
mkdir -p models
tar -xzf ../ai-models.tar.gz -C models/
Configure Environment
# Copy environment template
cp .env.example .env
# Edit .env and configure:
# - Set HUGGINGFACE_TOKEN (still required for model loading)
# - Set MODEL_CACHE_DIR=./models
# - Configure passwords and secrets
nano .env
Start Services
# Make script executable
chmod +x opentranscribe.sh
# Start in offline mode
docker compose -f docker-compose.yml -f docker-compose.offline.yml up -d
# Or using the script
./opentranscribe.sh start offline
Offline Configuration
The docker-compose.offline.yml file disables internet-dependent features:
- YouTube download worker disabled
- External network access restricted
- Model downloads disabled (uses local cache)
Local LLM for Offline AI Features
To use AI summarization in offline mode, deploy a local LLM:
Option 1: vLLM
# On separate GPU (recommended)
docker run --gpus '"device=0"' -p 8000:8000 \
vllm/vllm-openai:latest \
--model meta-llama/Llama-2-70b-chat-hf
Option 2: Ollama
# Install Ollama
curl -fsSL https://ollama.com/install.sh | sh
# Pull model (on internet machine, then copy)
ollama pull llama2:70b
Configure in .env:
LLM_PROVIDER=vllm # or ollama
VLLM_API_URL=http://your-server:8000/v1
Updating Offline Installation
To update an offline installation:
- On internet machine: Pull new Docker images
- Save to tarball
- Transfer to offline machine
- Load new images
- Restart services
Verification
# Check all services running
docker compose ps
# Verify no internet access attempts
docker compose logs | grep -i "connect\|download"
# Test transcription
# Upload a test file through web UI
Limitations
- Cannot download YouTube videos
- Cannot use cloud LLM providers (OpenAI, Claude, etc.)
- Cannot auto-update models
- Cannot provision (or re-provision) the native diarizer's weights on the air-gapped machine —
build the package with
scripts/build-offline-package.shand a validHUGGINGFACE_TOKENsomodels/diar-native/ships already populated (see above), or accept the automatic fallback to the in-process PyAnnote engine - ✅ All transcription features work
- ✅ Speaker diarization works (native engine if its weights shipped with the package, PyAnnote fallback otherwise)
- ✅ Local LLM works (if configured)