DEV Community

iMonitor Software
iMonitor Software

Posted on

A support desk on one small server: sizing, backups and the boring parts

Most "run your own help desk" guides stop at docker compose up. The interesting part starts three months later, when the disk fills up or a restore has to actually work.

Here is the unglamorous version, for a team of three to ten.

What actually consumes disk

Component Growth Notes
Message bodies + metadata slow thousands of tickets ≈ a few hundred MB/year
Attachments fast screenshots and PDFs dominate
Search index medium rebuildable, can be excluded from backups
Logs slow but relentless cap at 30 days, rotate
Database WAL / binlogs bursty the usual suspect when disk "suddenly" fills

Rule of thumb: plan for attachments to be 10× the database. A 2 GB database usually comes with a 20 GB attachment store.

A sizing that survives a year

For 5 agents, ~60 tickets/day, average 1.5 MB of attachments per ticket:

60 × 1.5 MB × 365 ≈ 33 GB/year of attachments
database + index         ≈ 3-5 GB/year
logs (capped)            ≈ 2 GB
------------------------------------------
one year                 ≈ 38-40 GB
Enter fullscreen mode Exit fullscreen mode

So: 80 GB of disk with retention pruning, or 200 GB if you keep attachments forever. Both are one cheap VPS.

The three cron jobs that matter

# 1. logical backup, compressed, off the same disk
0 2 * * *  pg_dump -Fc app | gzip > /backup/db-$(date +%F).dump.gz

# 2. attachments: rsync to a second location, not a tarball
30 2 * * *  rsync -a --delete /data/attachments/ /backup/attachments/

# 3. prune, with a count in the log so you can prove it ran
0 3 * * *  find /backup -name 'db-*.dump.gz' -mtime +14 -delete | wc -l
Enter fullscreen mode Exit fullscreen mode

Three details that save you later:

  • pg_dump -Fc, not a raw file copy. A copied data directory from a running server is not a backup.
  • rsync attachments, do not tarball them. Restoring one file should not require unpacking 20 GB.
  • Log the count. When someone asks "is the backup running?", the log answers.

The restore drill

Once a quarter, on a scratch machine:

  1. Create an empty database, pg_restore last night's dump
  2. Point the app at it, start it
  3. Open a six-month-old thread, download one attachment, send one test reply
  4. Note the elapsed time

If that takes more than an hour, your restore procedure is a project, not a procedure.

Mail is the part people forget

The app is not the only thing that breaks. If inbound mail flows through the same box, an outage means customers get bounces and you learn about it two days later.

Two options that both work:

  • MX at an independent provider, forwarding into the app over IMAP/SMTP. Mail keeps arriving during app downtime.
  • SMTP relay for outbound only, so deliverability does not depend on your server's IP reputation.

Do not put inbound mail on a hostname whose DNS lives inside the app server.

Backups are not the same as portability

A database dump restores your installation. Portability means you can also leave:

  • A per-ticket export (JSON or CSV with bodies and attachment paths)
  • Attachments stored under stable, guessable paths
  • No proprietary blob format for the search index

Test the export once. If it produces a zip you can open on a laptop, you are not locked in.

What I would not bother with at this size

  • Kubernetes. One compose file and a systemd unit is easier to debug at 2 a.m.
  • Read replicas. At 10 agents, the database is idle most of the day.
  • Object storage for attachments unless you already run it — a mounted disk with rsync is fine, and simpler to restore.
  • Elasticsearch. Postgres full-text search handles a few hundred thousand messages without complaint.

The minimum viable runbook

One page, printed and taped inside a cupboard:

  • Where the server is, and its IP (not only the hostname)
  • Where DNS is managed, and who can change it
  • How to restart the app, and how to tell it worked
  • Where backups land, and how to restore one
  • The escalation channel when the app is down

If the person who set it up is on holiday, that page is the difference between a 20-minute fix and a lost day.


Onsites AI ships as a compose stack — app, Postgres, queue worker, optional mail fetcher — with the self-hosting notes covering exactly the parts above. Free for the first three seats if you want to measure your own ticket volume before sizing anything.

Top comments (0)