How to install Ollama on Linux with models on external storage using Lindir

Install Ollama through Lindir fleet, put model files on an external disk, bind OLLAMA_HOST=0.0.0.0 for Tailnet clients, and start a user service only when you need inference.

A language model is not a small guest. Tens of gigabytes settle onto disk the way ice settles onto a quiet moon — harmless until you try to park everything on the same thin drive that boots the machine. Root filesystems are for systems. Expansion disks are for archives and weight.

This walkthrough assumes Linux Directory is already running and at least one host is enrolled. If you are still at first light, start with How to install Linux Directory (Lindir). We will place Ollama on a CachyOS workstation (here, Trantor), keep models on an Expansion volume, and leave a user systemd unit ready — started only when you ask. Each job is claimed on the next lindir-client sync; with the sync timer enabled, that is usually within a minute.


What we are arranging

Piece Choice
Package Distro ollama (Arch / CachyOS)
Models /run/media/user/Expansion/Models/ollama via OLLAMA_MODELS
Listen OLLAMA_HOST=0.0.0.0 so other machines on the Tailnet can reach the API
Package daemon System ollama.service stays disabled (it would use /var/lib/ollama on the root disk)
Our daemon Lindir-managed user unit lindir-ollama.service
Autostart Off — fleet service add enables immediately; we disable afterward

Lindir fleet services write ExecStart and optional WorkingDirectory. There is no dedicated Environment= field yet, so OLLAMA_MODELS and OLLAMA_HOST ride in the command with /usr/bin/env.


Credentials

Load the env file described in the install article:

set -a
source ~/.config/lindir/mcp.env
set +a
lindir-admin health
lindir-admin host list

Take the host’s UUID from the list. Expansion must be mounted before you start the daemon: the udisks path /run/media/user/Expansion appears only while the volume is attached. On exFAT, Models/ollama and Models/Ollama may be the same directory.


Create the models directory

A short fleet script creates the path on the host:

cat > /tmp/ollama-models-dir.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
MODELS=/run/media/user/Expansion/Models/ollama
test -d /run/media/user/Expansion
mkdir -p "$MODELS"
ls -ld "$MODELS"
du -sh "$MODELS" || true
EOF

lindir-admin fleet scripts create --name ollama-models-dir \
  --file /tmp/ollama-models-dir.sh --timeout-sec 60 \
  --description 'Ensure Ollama models directory on Expansion'

lindir-admin fleet scripts run --id SCRIPT_ID --host-id HOST_ID
lindir-admin fleet runs

Use the script id from create (or from lindir-admin fleet scripts) and the host id from host list. Wait until the run status is succeeded.


Install the package

lindir-admin fleet packages install --host-id HOST_ID --package ollama
lindir-admin fleet packages pending

When the job leaves pending, the package is on the host. Skip this if inventory already shows ollama.

CachyOS and Arch ship /usr/lib/systemd/system/ollama.service. That unit runs as the system user ollama, sets OLLAMA_MODELS=/var/lib/ollama, and is wanted by multi-user.target — a poor fit for a multi‑hundred‑gigabyte library when the root disk is nearly full.

lindir-admin fleet systemd disable --host-id HOST_ID --unit ollama.service

fleet systemd only operates existing system units; it does not write unit files. Confirm with lindir-admin fleet systemd-units --host-id HOST_ID that ollama.service is disabled.


Add a user service, then turn auto-start off

lindir-admin fleet service add --host-id HOST_ID \
  --scope user --username user --unit ollama \
  --command '/usr/bin/env OLLAMA_MODELS=/run/media/user/Expansion/Models/ollama OLLAMA_HOST=0.0.0.0 /usr/bin/ollama serve' \
  --working-directory /run/media/user/Expansion/Models/ollama \
  --timer-description 'Ollama — models on Expansion, listen all interfaces'

lindir-admin fleet service pending

After sync, Lindir writes ~user/.config/systemd/user/lindir-ollama.service, enables linger for that account by default, and runs enable --now. The daemon starts once.

Then remove automatic start:

lindir-admin fleet service disable --host-id HOST_ID \
  --scope user --username user --unit ollama
lindir-admin fleet service pending

disable stops the unit and clears the WantedBy link. The unit file remains. When Expansion is mounted and you want inference:

lindir-admin fleet service start --host-id HOST_ID \
  --scope user --username user --unit ollama

Stop with fleet service stop when you are finished.

lindir-admin fleet service list
lindir-admin fleet services --host-id HOST_ID

Successful add and disable jobs include a short systemctl transcript in stdout (the WantedBy symlink created or removed).


Verify

lindir-admin fleet runs
lindir-admin fleet service list
lindir-admin fleet services --host-id HOST_ID

A successful ollama-models-dir run prints ls and du on stdout. After disable, stdout should show the WantedBy symlink removed; after start, the job should exit 0.

With the service running, another Tailnet host can reach the API at http://trantor:11434 (or Trantor’s Tailscale IP), for example curl -fsS http://trantor:11434/api/tags.

Model pulls land under Expansion when OLLAMA_MODELS points there. The root filesystem keeps the OS, the GPU drivers, and the modest ollama package.


Why this shape

  1. Disk — Models live on Expansion, not on /.
  2. Package vs policy — Distro ollama.service suits a server that should always listen under /var/lib/ollama. A workstation with a detachable library wants a different unit and path.
  3. Demand — Inference is intentional. Disabling after fleet service add keeps Lindir as author of the unit without making Ollama part of every boot.
  4. Directory — Identity and fleet share one control plane: Fleet, Admin CLI.

Caveats

  • Mount first. /run/media/.../Expansion is a udisks mount. Attach and mount the disk before fleet service start.
  • exFAT — Ownership semantics are shallow; treat the volume as a library path for the session user, not as a multi-user ACL surface.
  • No API authentication. OLLAMA_HOST=0.0.0.0 exposes the API on every interface, including the Tailscale address. Treat the Tailnet as the trust boundary; do not forward port 11434 to the open internet without an auth proxy.
  • Linger — User-scope Lindir services enable linger so start and stop work without a graphical login. That is still the account’s user manager, not the system ollama user.
  • Sync — Jobs stay pending until lindir-sync.timer claims them — usually within a minute on a healthy agent.

When the directory can see the host, large models can live where there is room — and wake only when you call them.