SSD Nodes Learn 🎉 VPS from $5.50/mo
Guides Matt ConnorBy Matt Connor

Ollama pull vs run, and where models live

ollama pull downloads a model and stops. ollama run downloads it, then opens a chat. Where the files land, why they fill a VPS root disk, how to move them.

ollama pull vs ollama run

ollama pull downloads a model and stops. ollama run downloads the model only if it is missing, then loads it into memory and opens an interactive chat. The download is identical and the files land in the same place. Only run keeps going afterwards.

That one difference decides which command belongs in a script and which one belongs at a keyboard.

ollama pull gemma4
ollama run gemma4
ollama run gemma4 "Reply with one word: ready"

The first line fetches the model and exits, so it is safe in provisioning and in a systemd unit. The second opens a chat session; type /bye or press Ctrl+D to leave it. The third sends a single prompt, prints the answer and exits, which is the form a script wants when it needs an answer rather than a session. Model names move quickly, so treat gemma4 here as a placeholder: it is the example the official Ollama documentation uses as of August 2026, and any tag from the library behaves the same way.

Why the first ollama run looks like it has frozen

A first run on a fresh VPS can sit with no output for several minutes. Nothing is broken. The chat prompt cannot appear until the model is on disk and loaded into memory, so run is doing a multi-gigabyte download before it has anything to show you.

Two things hide that work. Ollama draws its progress bar only when its output is a terminal, so a run inside a shell script, a cron job, a CI step or a plain ssh host ollama run ... prints nothing at all while it downloads. Then, once the bytes have landed, the file still has to be read from disk into RAM before the first token, and on a small VPS that read is slow. If the box does not have the memory for the model, the kernel starts swapping and the wait grows much longer.

Watch it from a second session instead of guessing:

df -h /
watch -n5 df -h /

Free space falling in steps means the download is still running. Free space that stops falling while the command is still busy means the download finished and the load into memory has started.

This is the argument for pulling ahead of time. The person who types ollama run should never be the one paying for the download.

Pull the model before anyone asks for it

On a new box, pull in the same script that installs the server:

curl -fsSL https://ollama.com/install.sh | sh
ollama pull gemma4

If you are standing the server up for the first time, the full Ollama on a VPS install covers the service itself and who is allowed to reach it. After that, the thing worth setting up is a pull that outlives your terminal, because a download killed halfway through is how people end up with a half-populated model store.

Run it inside tmux, or hand it to systemd as a one-shot unit that runs at boot. Write /etc/systemd/system/ollama-pull.service:

[Unit]
Description=Pre-pull Ollama models
Wants=ollama.service network-online.target
After=ollama.service network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c 'until ollama list >/dev/null 2>&1; do sleep 2; done'
ExecStart=/bin/sh -c 'ollama pull gemma4'

[Install]
WantedBy=multi-user.target

Both commands run through /bin/sh -c on purpose. A bare ExecStart= needs an absolute path, and the installer does not always put the binary in the same directory, so command -v ollama on your own box is the only reliable answer. Going through the shell uses the service PATH instead of a path copied from a guide. The first ExecStart matters as well: After=ollama.service means the server unit was started, which is not the same as ready, so the loop waits until ollama list answers before the pull begins.

sudo systemctl daemon-reload
sudo systemctl enable --now ollama-pull.service
journalctl -u ollama-pull.service

The journal should show the pull finishing with no error, and ollama list should then show the model. To keep a moving tag current, add a systemd timer or a weekly cron entry that runs the same pull. Re-pulling a tag that has moved downloads the new layers and leaves the old ones with nothing pointing at them, and those are cleaned up the next time the server starts.

What happens when a pull is interrupted

Every layer of a model is stored under a hash of its own contents. An interrupted pull is therefore not wasted work: run the same ollama pull again, and the layers that already finished are recognised and skipped, so the download continues with the layer that was cut off.

One action destroys that progress. When the Ollama server starts, it removes stored layers that no model manifest refers to, and the partial layer left by a dead pull is exactly that. So restarting the service before you retry throws away the piece you already downloaded. Retry the pull first and restart later. If a partial download genuinely has to survive a restart, set OLLAMA_NOPRUNE=1 in the service environment, then take it back out, because that startup cleanup is what stops orphaned layers from collecting on the disk.

If the pull died with no space left on device, free space before retrying. If df reports a full disk and du on the model directory does not account for it, the space went somewhere else, and the reasons df and du disagree are worth reading before you delete anything.

Where does Ollama store models on a VPS?

Ask your own box rather than trusting a path from any guide, including this one. The location differs between a package install and a container, and it changes again if anyone has set OLLAMA_MODELS.

systemctl cat ollama.service
getent passwd ollama
sudo find / -xdev -type d -name blobs 2>/dev/null

systemctl cat prints the unit file together with every drop-in, so an OLLAMA_MODELS line set by you or baked into your image shows up there. With no such line, the store sits under the home directory of the account the service runs as, and getent passwd prints that home directory in the sixth colon-separated field. The find searches one filesystem for the blobs directory, which is where the layers are actually written. Drop -xdev if the models may already be on a separate mount.

Now measure, and read your own numbers:

ollama list
df -h /
sudo du -sh /the/directory/you/found
sudo du -h -d1 /the/directory/you/found

The store has two parts. manifests holds one small file per model tag, and that file lists the layers the tag is built from. blobs holds the layers themselves, each named after the hash of its contents, and almost all of the size is there. Because layers are shared between tags, two models built on the same weights each report their own size in ollama list while occupying that space once on disk, so the listed sizes can add up to more than du reports for the directory.

Model files fill a small VPS root filesystem faster than anything else you are likely to install, and the largest single lever on their size is the weight format. Choosing between q4, q8 and fp16 is worth gigabytes per model.

Move the models to a data volume with OLLAMA_MODELS

If the plan has a second disk or a larger data volume, move the store before the root filesystem fills. Stop the server first, so you do not copy a file that is still being written.

sudo systemctl stop ollama
sudo mkdir -p /mnt/data/ollama-models
sudo rsync -a /the/directory/you/found/ /mnt/data/ollama-models/
sudo chown -R ollama:ollama /mnt/data/ollama-models
sudo systemctl edit ollama.service

systemctl edit opens an editor on a drop-in file, so the packaged unit stays untouched and a package upgrade cannot overwrite your change. Add these two lines:

[Service]
Environment="OLLAMA_MODELS=/mnt/data/ollama-models"
sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl show ollama --property=Environment
ollama list

systemctl show should print your new path, and ollama list should show the same models it showed before the move. An empty list means the server cannot read the new directory. The service runs as the ollama user, so that user needs read and write access to the destination, which is the job of the chown line above. Check journalctl -e -u ollama for permission errors naming the new path. Delete the old copy only after the list is correct, because a failed move plus a deleted source means downloading everything again.

The other option keeps the original path and mounts the data volume onto it:

echo '/mnt/data/ollama-models /the/directory/you/found none bind 0 0' | sudo tee -a /etc/fstab
sudo mount -a
findmnt /the/directory/you/found
df -h /

findmnt printing the mount means the bind is live. A bind mount helps when something else on the box already expects the default location. It has one trap: the files you copied out are still sitting under the mount point on the root disk, hidden by the mount, so the space is not returned until you unmount and remove them. The environment variable is the easier of the two to explain to whoever logs in next.

Where a container keeps them instead

The official image stores models in whatever you mount, not in any host directory belonging to an ollama user. The documented run command is:

docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama

ollama before the colon is a named Docker volume, and /root/.ollama is where the server writes inside the container. So du against the paths from the previous section finds nothing, because nothing is there. Print the real location and size:

docker volume inspect ollama
docker system df -v
docker exec -it ollama ollama list

Read the Mountpoint field from docker volume inspect, then run sudo du -sh against it. To put the models on a data volume, replace the named volume with a host directory (-v /mnt/data/ollama:/root/.ollama) and recreate the container. The container writes as root, so that host directory ends up owned by root. Under rootless Podman the ids are mapped into your user's subuid range instead, so host ownership looks different again: running Ollama under rootless Podman covers that mapping.

One warning about cleanup. docker volume prune removes every volume that no container refers to. Remove or recreate the ollama container without its volume and a later prune deletes every model you downloaded, with no way back except downloading them again. Read how to prune Docker disk usage on a VPS before running prune on a box that hosts models.

Remove a model with ollama rm, not with rm

ollama list
ollama rm gemma4
ollama list
df -h /

ollama rm deletes the manifest for that tag, then deletes the layers no remaining manifest refers to. The space comes back as soon as those files are unlinked, so df moves straight away. Because layers are shared, removing one of two closely related tags can free far less than the size ollama list printed next to it. That is correct behaviour, not a failed delete.

Deleting files by hand breaks the pair. Remove a blob with rm and the manifest still lists it, so ollama list keeps showing the model and any attempt to use it fails when the missing layer is read. Remove a manifest by hand and its layers stay on disk with nothing pointing at them, holding space that no Ollama command will report to you. If you have already done it, ollama rm on the tag clears the leftover entry, and restarting the server clears layers that nothing refers to.

One last distinction, because the two get mixed up constantly. ollama rm is about disk. ollama stop gemma4 unloads a model from memory and frees no disk at all. How long a model stays resident in RAM once the download is finished is a separate setting, and keeping a model loaded instead of reloading it on every request covers it.

FAQ

What is the difference between ollama pull and ollama run?

ollama pull downloads a model to disk and exits. ollama run checks whether the model is already on disk, downloads it if it is not, loads it into memory and then opens an interactive chat session. Both write the same files to the same directory. Use pull in provisioning and in scripts, and use run when a person is at the keyboard. ollama run <model> "your prompt" sends one prompt and exits, which is the scriptable form of run.

Why does my first ollama run seem to hang?

It is downloading. The chat prompt cannot appear until the model is on disk and loaded into memory, and a model is several gigabytes. Ollama draws its progress bar only when output is a terminal, so a run inside a script, a cron job or an ssh host ollama run ... shows nothing at all while it works. Open a second session and run watch -n5 df -h /: free space falling in steps means the download is in progress. Pull the model in advance and the wait disappears.

Where does Ollama store its models?

The location depends on the install, so print it rather than assuming. Run systemctl cat ollama.service to see whether OLLAMA_MODELS is set in the unit or a drop-in. If it is not, the store lives under the home directory of the account the service runs as, which getent passwd ollama prints. sudo find / -xdev -type d -name blobs 2>/dev/null locates the layer directory directly. For the container image, the store is inside the mounted volume, and docker volume inspect ollama prints its host Mountpoint.

How do I move Ollama models to another disk?

Stop the service, copy the store to the new location with rsync -a, give the directory to the service account with sudo chown -R ollama:ollama <directory>, then run sudo systemctl edit ollama.service and add Environment="OLLAMA_MODELS=<directory>" under a [Service] line. Reload with sudo systemctl daemon-reload and restart. Confirm with systemctl show ollama --property=Environment and ollama list. An empty list almost always means the ollama user cannot read the new directory; journalctl -e -u ollama will name the path.

Does deleting the model files free the space?

Deleting files by hand frees the bytes but leaves the store inconsistent. Remove a blob and the manifest still lists that model, so it keeps appearing in ollama list and fails when used. Remove a manifest and its layers remain on disk with nothing referring to them. Use ollama rm <model>, which deletes the manifest and then the layers no other model needs. If files were already deleted by hand, run ollama rm on the tag to clear the entry, then restart the server, which removes layers that no manifest refers to.