How I Built a Simple Offline Documentation Server for Teams with Patchy Internet
A practical, low-cost playbook to serve your team's docs on a local network or cheap VPS so engineers can read, search, and keep working when internet is slow.
Written by: Devika Iyer
We once had a week where the office internet kept dropping to a painfully slow 2G-equivalent. Engineers couldn’t load API docs, onboarding guides, or our internal runbooks — and tickets piled up because people couldn’t find the single command to rotate a key. That’s when I built a small offline documentation server that lives on our LAN (and syncs to a cheap VPS for remote access). It cost us very little, and the team stopped blaming the network for every slowdown.
If your team ships to offices with flaky internet, offshore contractors with poor bandwidth, or people who travel with spotty mobile data, an offline documentation server solves a lot of friction. Here’s a practical playbook you can replicate in a day.
Why run an offline documentation server
- Reliability: Docs are available even when the internet is down.
- Speed: Local serving removes page load penalties for large search indices or images.
- Privacy: Internal procedures and secrets in runbooks don’t depend on a third-party SaaS. Main tradeoff: you’ll need a simple sync process and someone to own updates (it’s not fully automatic—more on that later).
What I run (the minimal stack that just works)
- Content: Markdown in a Git repo (we already had docs in a repo).
- Generator: MkDocs + mkdocs-material (lightweight, full-text search with lunr, easy theme).
- Server: A small machine — Raspberry Pi 4 at the office or a ₹300–₹700/month VPS for remote access.
- Reverse proxy: Caddy (automatic TLS if public) or nginx for local LAN.
- Sync: git + post-receive hook or a cron rsync from the canonical repo.
- Optional remote access: Tailscale for secure, no-config remote access (instead of exposing ports).
Main keyword: offline documentation server appears below to emphasise the focus and how I used it.
Step-by-step: the quick path I used (can be done in ~60 minutes)
-
Author your docs as Markdown in a repo Keep things simple: quick-start, runbooks, API examples, and an FAQ. If you already use a monorepo, create docs/ and add mkdocs.yml.
-
Install MkDocs and a simple theme On the server (Pi or VPS):
- python3 -m venv venv && source venv/bin/activate
- pip install mkdocs mkdocs-material Initialize: mkdocs new . and edit mkdocs.yml and nav.
- Build and serve locally for dev
- mkdocs serve This gives you a live-reload on localhost for authoring. Build static: mkdocs build outputs site/.
- Serve the static site on the LAN
- For development or small teams: python -m http.server 8000 —directory site
- For production LAN: use Caddyfile:
- caddy reverse-proxy or static file serving from site/ (Caddy makes TLS painless if you want public). Point your office router’s DNS (or your Pi’s avahi/Bonjour) to make docs.local resolvable.
-
Add search that works offline MkDocs’ built-in search uses lunr.js and is shipped with the generated site. It keeps everything client-side, so full-text search still works without network calls.
-
Keep the server in sync Option A — Push hook (recommended): On your canonical repo, add a Git remote pointing to the server. On the server, a bare repo with a post-receive hook runs mkdocs build into the served directory. Option B — Cron pull: simple cronjob that git pull && mkdocs build every 10 minutes. Option C — rsync a built site from CI (if you want controlled builds).
-
Remote access with security If you need remote access, use Tailscale or authorize a small VPS (Caddy + HTTPS). Tailscale avoids opening ports and works well in India where home routers/NAT can be finicky.
Practical constraints and tradeoffs I learned
- Update latency: With cron pulls or push hooks you’ll usually be within minutes of updates. But it’s not instant unless you push hooks reliably. Accept that small lag.
- Search size: Lunr.js builds a client-side index. For very large docs (tens of thousands of pages), the search index can balloon and slow clients on low-end devices. In that case, consider a small local search backend (whoosh on the server) and an API — but that reintroduces runtime dependencies.
- Auth and access control: If docs are sensitive, avoid exposing the server publicly. Tailscale or VPNs are easier than building auth into a static site.
- Maintenance: A Raspberry Pi is cheap and quiet, but you’ll need to handle OS updates and occasional SD card failures. A small VPS offloads hardware but costs recurring money (~₹300–₹1000/month depending on provider).
Why this is better than “just use Google Drive” Because a documentation site is searchable, linkable, versionable, and readable on mobile without scrolling a Google Doc. It becomes the single source of truth that works whether the internet is fine or not. We stopped seeing “I can’t open the doc” Slack threads — the team had a local URL they trusted.
When it’s not worth it
- If your team is tiny (two people) and always on high-quality internet, the overhead isn’t justified.
- If docs change multiple times a day and you need instantaneous global updates, you’ll need to build a push pipeline.
Final notes Start small: pick one critical set of docs (oncall runbook or deployment steps), get it working on a Pi in your office, and measure the reduced time-to-resolution in incident playbacks. The biggest win is psychological — people stop assuming the network will be the cause of every problem. For us, that meant fewer blocked PRs, fewer late-night escalations, and a calmer office when the ISP had “one of those days.”
If you want, I can share the short bash post-receive hook and the Caddyfile I use — they’re low-friction and save a surprising amount of time.