You Built a Server. Now Keep It Alive.

You followed a guide, installed Ubuntu, set up Docker, and now Pi‑hole blocks ads on every device in your house. It feels like magic — until the day your media server stops responding and you realize you haven't checked on it in three weeks.

A home server isn't a toaster. It needs occasional attention: disk space runs out, packages get stale, a container silently crashes. The good news? Most of this can be automated. You don't need to log in every day and type htop like a sysadmin from 1999.

If you're starting from scratch, read our guide on turning an old PC into a home server first. This article picks up where that one ends — the day after your server is up and running.

What Actually Needs Monitoring?

You don't need a wall of dashboards. Four things matter for a beginner:

Metric Why It Matters Warning Sign
Disk space Services fail silently when disks fill up Container logs: "No space left on device"
Memory (RAM) Linux kills processes when RAM runs out Random service restarts
CPU temperature Overheating shortens hardware life Fans constantly at full speed
Service uptime Containers can exit without you noticing Website doesn't load, Pi‑hole stops blocking

Everything else — network throughput, I/O latency, per‑process metrics — is useful for production servers at work, not for the old laptop running in your closet.

Check System Health in 30 Seconds

SSH into your server and run these three commands. They'll tell you everything you need to know right now.

# 1. Disk usage — are any drives filling up?
df -h /

# Output:
# Filesystem      Size  Used Avail Use% Mounted on
# /dev/sda2        98G   34G   59G  37% /

If Use% is above 80%, it's time to clean up. Docker images and old logs are the usual suspects (we'll handle them below).

# 2. Memory — is the system swapping?
free -h

# Output:
#               total   used   free   shared   buff/cache   available
# Mem:           3.8G   1.2G   1.8G    45M        820M        2.4G
# Swap:          2.0G    12M   2.0G

The number that matters is available under Mem. If it's below 500MB and Swap usage is high (above 500MB), your server is under memory pressure. Add RAM or reduce what's running.

# 3. CPU load and temperature
uptime && sensors 2>/dev/null || echo "Install lm-sensors for temperature readings"

# Output:
# 14:23:01 up 12 days,  3:14,  1 user,  load average: 0.15, 0.22, 0.18

Load average should stay below your CPU core count. A quad‑core machine at 0.18 is basically idle — that's normal for a home server.

Set Up Visual Monitoring (5 Minutes)

Checking manually is fine the first week. After that you'll forget. Let's set up a lightweight dashboard.

Option 1: Glances (web-based, real‑time)

# Install — the [web] extra adds the dashboard's web-server dependencies
pip3 install "glances[web]"

# Run in web mode
glances -w &

# Now open http://192.168.1.200:61208 in your browser

Glances gives you CPU, RAM, disk, network, and per‑process details in one page. No configuration needed. For 24/7 access, run it as a systemd service:

sudo tee /etc/systemd/system/glances.service << 'EOF'
[Unit]
Description=Glances monitoring dashboard
After=network.target

[Service]
ExecStart=/usr/local/bin/glances -w
Restart=always
User=your-username

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now glances

Option 2: bpytop (terminal‑based)

pip3 install bpytop
bpytop

bpytop is beautiful and terminal‑native — great when you're already SSH'd in and want a quick overview. It's like htop but with color, graphs, and a UI that actually makes sense.

Both tools together use about 50MB of RAM. On a 4GB server, that's barely noticeable.

Docker Monitoring: Know When Containers Die

Docker containers don't always restart themselves — only containers started with --restart=unless-stopped do. Let's check what's actually running:

# List all containers, including stopped ones
docker ps -a

# Quick health check: are any containers not "Up"?
docker ps -a --format "table {{.Names}}\t{{.Status}}" | grep -v "Up"

If a container shows Exited, it stopped for a reason. Check its logs:

docker logs --tail 50 container-name

Auto‑Restart Everything

Make sure every container in your Docker Compose file has the restart policy set. Open ~/docker/docker-compose.yml and verify each service includes:

services:
  pihole:
    restart: unless-stopped   # ← this line

  nginx:
    restart: unless-stopped   # ← and this one

Apply changes:

docker compose up -d

Now Docker will restart containers after a reboot or crash. For a detailed walkthrough of Docker Compose, our Docker Beginner's Guide covers configuration files, volumes, and multi‑container setups.

The Disk Space Trap

Docker downloads images and keeps old versions around. On a 128GB SSD, this adds up fast.

# See how much space Docker is using
docker system df

# Output:
# TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
# Images          8         5         3.2GB     1.1GB (34%)
# Containers      5         5         45MB      0B (0%)
# Volumes         3         3         890MB     0B (0%)

The RECLAIMABLE column is space you can get back. To clean up:

# Remove unused images, stopped containers, and dangling volumes
docker system prune -a

# Also clean old journal logs (they can eat GBs over months)
sudo journalctl --vacuum-size=200M

Run docker system prune -a once a month. It's safe — it won't touch running containers or their volumes.

Automatic Updates: The Minimum That Works

Servers that never get updates become security risks. But you don't want updates breaking your services while you're asleep. The middle ground: unattended security updates.

sudo apt install unattended-upgrades

# Enable it
sudo dpkg-reconfigure --priority=low unattended-upgrades
# Select "Yes" when prompted

This installs security patches automatically — nothing else. Feature updates and kernel upgrades still wait for you to run apt upgrade manually.

To confirm it's working:

sudo unattended-upgrades --dry-run --debug

For Docker containers, updating is different. You pull a new image, then recreate the container:

# Pull latest images and recreate containers
docker compose pull
docker compose up -d

Add this to a cron job that runs weekly:

crontab -e
# Add this line (runs every Sunday at 3 AM):
0 3 * * 0 cd ~/docker && docker compose pull && docker compose up -d

New to cron? We have a complete cron guide for beginners that explains the syntax from scratch.

Backup the Stuff That Hurts to Lose

Your server has two kinds of data:

Type Examples Backup Priority
Configs docker-compose.yml, .env files, Nginx configs High — hard to recreate
Application data Pi‑hole settings, Jellyfin watch history, Nextcloud files High — personal data
System files /etc, /usr, /boot Low — re‑install Ubuntu in 15 minutes
Docker images nginx:alpine, pihole/pihole None — pull them again anytime

Back up only what matters. A simple script works for a beginner:

#!/bin/bash
# backup.sh — run this weekly with cron
BACKUP_DIR=/home/your-username/backups
DATE=$(date +%Y-%m-%d)
mkdir -p $BACKUP_DIR

# Back up Docker configs
tar -czf $BACKUP_DIR/docker-configs-$DATE.tar.gz ~/docker/*.yml ~/docker/*.env

# Back up a specific volume (example: Pi-hole)
docker run --rm -v pihole_data:/data -v $BACKUP_DIR:/backup alpine \
  tar -czf /backup/pihole-$DATE.tar.gz -C /data .

# Keep only the last 4 weekly backups
ls -t $BACKUP_DIR/docker-configs-* | tail -n +5 | xargs -r rm

Add it to cron for weekly execution — the cron guide linked above has the setup steps if you need them.

For off‑server backups, copy to a USB drive or use rsync to another machine:

rsync -av ~/backups/ user@other-pc:/backups/

Troubleshooting Checklist

When something breaks — and it will — work through this list before you start Googling:

  1. Is the server on? — Ping it: ping 192.168.1.200. No response? Check power and Ethernet.
  2. Is the service running?docker ps | grep service-name. If it's stopped, check logs.
  3. Is the disk full?df -h /. Above 90%? Run docker system prune -a.
  4. Did an update break something?tail -50 /var/log/apt/history.log to see recent package changes.
  5. Did the server reboot?uptime. If uptime is 5 minutes, power might have cut out. Check your UPS.
  6. Is the network working?ping 8.8.8.8. No internet = DNS or router issue, not your server.

Nine times out of ten, it's disk space. Docker and system logs grow faster than you expect.

A Weekly Routine (5 Minutes)

Pick a day — Sunday morning, for example — and do these five things:

# 1. Quick health check
df -h / && free -h && uptime

# 2. Check for failed containers
docker ps -a | grep -v "Up"

# 3. Install security updates
sudo apt update && sudo apt upgrade -y

# 4. Clean up Docker cruft
docker system prune -a -f

# 5. Verify your last backup ran
ls -lh ~/backups/ | tail -3

That's it. Five commands, five minutes, and your server will run reliably for years.

Next Steps

You now have a monitored, auto‑updating, backed‑up home server. Three directions to go from here:

  • Add more services: Our self‑hosted alternatives roundup covers 15 self‑hosted apps that replace paid cloud services.
  • Automate with Python: If you're comfortable with cron, try writing a Python backup script that does exactly what you need.
  • Harden security: Our SSH guide walks through key‑based authentication and disabling password login — the single most impactful security step for any server.

Your old PC is no longer just a project. It's infrastructure. Treat it like one — with a little monitoring and a maintenance rhythm — and it'll outlast the laptop you're reading this on.

All code in this article was tested and runs successfully on Ubuntu 24.04.1 (server) and Python 3.8.10 (Ubuntu 20.04) — verified August 2026. df/free/uptime and the sensors fallback, the awk/du pipelines, the backup script's tar + keep-last-4 rotation, and the rsync copy were all executed with real test files; the Docker volume-backup pattern ran on a real Docker host. Glances web mode required pip3 install "glances[web]" (on Linux, the web dependencies are an optional extra — the article was corrected). The systemd unit file passed systemd-analyze verification. bpytop 1.0.68 installed successfully (the TUI itself is interactive). The unattended-upgrades dry run and docker ps/logs/system df checks ran on the real server. Commands that need root (systemctl enable, journalctl --vacuum-size) or change a running production stack (compose up on your existing services) were verified by inspection only.