AI Infrastructure·8 min read·

Disk Layout for Models, Caches, and Indexes

Put models, embedding caches, git clones, and SQLite indexes on separate paths so a full cache cannot bury the OS on a single Lucknow VPS disk.

NB

Netbay Developer Relations

Netbay Engineering

On this page

A RAG box dies from disk the same way it dies from RAM: one directory grows until the OS cannot write logs or WAL. Models, Hugging Face caches, GGUF files, git clones, SQLite indexes, and prompt caches are different lifetimes and different sizes. They should not share /root or /tmp. This post is a directory tree, permissions, and a few commands that keep High-Speed SSD honest on a single Lucknow VPS.

One tree under /var/lib/rag

Give the service user ownership of a single prefix. Keep the OS on /. Keep the application checkout under /opt or /home. Keep all mutable RAG state under /var/lib/rag. That prefix is what you back up, du, and snapshot.

Suggested layout:

  • /var/lib/rag/models — pinned GGUF and sentence-transformer snapshots you copied on purpose
  • /var/lib/rag/hf — HF_HOME so transformers does not fill /root/.cache
  • /var/lib/rag/cache — embed_cache.db and prompt_cache.db
  • /var/lib/rag/index — chunks.db or the Postgres data directory if Postgres is dedicated to this
  • /var/lib/rag/repos — git clones the ingest timer pulls
  • /var/lib/rag/state — last_sha and lock files
  • /var/lib/rag/tmp — working files with tmpwatch or a systemd tmpfiles rule
bash
sudo useradd --system --home /var/lib/rag --shell /usr/sbin/nologin rag
sudo mkdir -p /var/lib/rag/{models,hf,cache,index,repos,state,tmp}
sudo chown -R rag:rag /var/lib/rag
sudo chmod 750 /var/lib/rag
sudo tee /etc/tmpfiles.d/rag.conf >/dev/null <<'EOF'
d /var/lib/rag/tmp 0750 rag rag 2d
EOF

Point the units at the tree. HF_HOME=/var/lib/rag/hf. TRANSFORMERS_CACHE is legacy; HF_HOME is enough. SENTENCE_TRANSFORMERS_HOME can sit under hf. Do not let a first API call download 400 MB into /root while you are watching /var.

If Postgres is the vector store, its datadir is /var/lib/postgresql already. Do not hide a second copy under rag/index. Point the app at localhost and treat pg_dump as the index backup. SQLite users put chunks.db in /var/lib/rag/index and include it in restic or rsync.

Pin models, ignore surprise downloads

Copy the exact MiniLM snapshot and any GGUF into /var/lib/rag/models with a version in the path. Load from that path. Set TRANSFORMERS_OFFLINE=1 in the systemd unit once the files exist. An accidental download during a traffic spike is how you fill the disk and stall ingest.

ini
[Service]
User=rag
Group=rag
Environment=HF_HOME=/var/lib/rag/hf
Environment=TRANSFORMERS_OFFLINE=1
Environment=TMPDIR=/var/lib/rag/tmp
WorkingDirectory=/var/lib/rag
ExecStart=/opt/rag/venv/bin/python /opt/rag/api.py

du -x -h --max-depth=2 /var/lib/rag weekly. Alert when the filesystem that holds /var is over 80 percent. Inodes matter if you clone many tiny git objects. df -i next to df -h.

Caches are disposable. Models are not, unless you can re-download from a pin you recorded. Indexes can be rebuilt from git plus the encoder, but rebuild time is hours on CPU. Backup index and models. Do not bother backing up prompt_cache.db. Embed cache is a maybe: it is rebuildable and large.

What not to colocate

Do not put this tree on a network share. Do not put it in the application git checkout where a deploy rsync --delete will wipe the index. Do not symlink models into /tmp. Do not run docker with anonymous volumes for the index unless you know where the volume lives and how to back it up. A VPS with one High-Speed SSD disk is simpler if you skip that.

Logs stay in journald or /var/log. Rotated logs should not sit next to GGUFs. Core dumps from an OOM can be multi-gigabyte; disable them or point them at a capped directory.

Lucknow DC01 is the only Netbay location. There is no second-region copy. Off-box backup is rsync or restic to a machine you control. L3/L4 DDoS filtering does not protect a world-readable /var/lib/rag. Mode 750 and a dedicated user are the control.

Intel Xeon Platinum will read model weights from page cache after the first load. Cold start still wants the files local and sequential. Fragmenting models across a nearly full filesystem is how cold start turns into 30 seconds of wait. Leave 15 to 20 percent free.

/var/lib/rag on one VPS disk models pinned weights hf HF_HOME only cache sqlite blobs index chunks.db repos git clones user rag, mode 750, TRANSFORMERS_OFFLINE=1 backup models + index; caches are disposable leave 20 percent free on High-Speed SSD not /root/.cache, not /tmp, not the git deploy

Takeaway

One prefix, one user, pinned models, disposable caches, and a backup of the index. Disk layout is RAG operations. You can spin up an Ubuntu 24.04 instance on Netbay in Lucknow in under 60 seconds and create /var/lib/rag before the first download — netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance