Set Up a Raspberry Pi as a Home Server for Self-Hosting Everything

Set Up a Raspberry Pi as a Home Server for Self-Hosting Everything


A Raspberry Pi is one of the best investments you can make if you want to self-host services at home. For under $100, you get a silent, low-power computer that can run 24/7, serving as a file server, media center, ad blocker, VPN endpoint, and much more — all without the electricity bill of a full-size server.

This guide walks you through setting up a Raspberry Pi 4 or 5 as a proper home server with Docker, so you can easily deploy and manage dozens of services.

What You Need

ComponentRecommendationApprox. Cost
Raspberry Pi 4 (4GB) or Pi 5 (8GB)Pi 5 preferred for better performance$60–$80
MicroSD card (32GB+) or USB SSDSSD strongly recommended for reliability$15–$40
USB-C power supply (5V 3A / 5V 5A for Pi 5)Official Raspberry Pi PSU$10
Ethernet cableCat5e or Cat6$5
Case with passive coolingArgon ONE or Flirc$15–$25

Total: ~$100–$170

An SSD connected via USB 3.0 dramatically improves performance and longevity over a microSD card. For the Pi 5, an NVMe HAT with an M.2 drive is the best option.

Step 1: Install Raspberry Pi OS

Download and install the Raspberry Pi Imager from raspberrypi.com/software.

  1. Insert your microSD card (or USB SSD) into your computer
  2. Open Raspberry Pi Imager
  3. Click Choose OSRaspberry Pi OS (other)Raspberry Pi OS Lite (64-bit)
  4. Click Choose Storage and select your card/drive
  5. Click the gear icon (⚙️) to configure:
    • Set hostname: piserver
    • Enable SSH (use password authentication)
    • Set username and password
    • Configure Wi-Fi (optional — Ethernet is preferred)
    • Set locale settings
  6. Click Write

Raspberry Pi OS Lite is headless (no desktop environment), which saves resources for server tasks.

Step 2: First Boot and SSH Access

  1. Insert the card/drive into the Pi and plug in Ethernet + power
  2. Wait 1–2 minutes for it to boot
  3. Find the Pi’s IP address from your router’s admin panel, or use:
# From another machine on the same network
ping piserver.local
  1. SSH into the Pi:
ssh youruser@piserver.local

Step 3: Initial System Configuration

Update the system and install essentials:

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git vim htop

Set a Static IP Address

Edit the network configuration so your Pi always gets the same IP:

sudo nmcli con mod "Wired connection 1" \
  ipv4.addresses 192.168.1.100/24 \
  ipv4.gateway 192.168.1.1 \
  ipv4.dns "1.1.1.1,8.8.8.8" \
  ipv4.method manual

sudo nmcli con up "Wired connection 1"

Replace the IP addresses with values appropriate for your network.

Enable Automatic Security Updates

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

If you’re using a USB SSD alongside a microSD card, you can boot directly from the SSD for much better performance:

  1. Flash Raspberry Pi OS to the SSD using Raspberry Pi Imager
  2. Update the Pi’s bootloader to prefer USB boot:
sudo raspi-config

Navigate to Advanced OptionsBoot OrderUSB Boot.

  1. Shut down, remove the microSD card, and power on — the Pi should boot from the SSD.

Step 5: Install Docker

Docker makes it simple to run isolated services without dependency conflicts:

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

Log out and back in, then verify:

docker --version
docker run hello-world

Install Docker Compose

Docker Compose comes with modern Docker installations. Verify:

docker compose version

Step 6: Create a Docker Compose Stack

Create a directory for your server configuration:

mkdir -p ~/server && cd ~/server

Create docker-compose.yml:

version: "3.8"

services:
  # Pi-hole: Network-wide ad blocking
  pihole:
    image: pihole/pihole:latest
    container_name: pihole
    restart: unless-stopped
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "8080:80/tcp"
    environment:
      TZ: "Asia/Kolkata"
      WEBPASSWORD: "your-secure-password"
    volumes:
      - ./pihole/etc:/etc/pihole
      - ./pihole/dnsmasq:/etc/dnsmasq.d
    dns:
      - 127.0.0.1
      - 1.1.1.1

  # Portainer: Docker management UI
  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer
    restart: unless-stopped
    ports:
      - "9443:9443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./portainer_data:/data

  # Nginx Proxy Manager: Reverse proxy with SSL
  nginx-proxy-manager:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "81:81"
    volumes:
      - ./npm/data:/data
      - ./npm/letsencrypt:/etc/letsencrypt

  # File Browser: Web-based file manager
  filebrowser:
    image: filebrowser/filebrowser:latest
    container_name: filebrowser
    restart: unless-stopped
    ports:
      - "8082:80"
    volumes:
      - /home:/srv
      - ./filebrowser/database.db:/database.db
    environment:
      PUID: 1000
      PGID: 1000

  # Uptime Kuma: Service monitoring
  uptime-kuma:
    image: louislam/uptime-kuma:latest
    container_name: uptime-kuma
    restart: unless-stopped
    ports:
      - "3001:3001"
    volumes:
      - ./uptime-kuma:/app/data

Start everything:

docker compose up -d

Step 7: Access Your Services

After the containers start, access them from any device on your network:

ServiceURLPurpose
Pi-holehttp://192.168.1.100:8080/adminAd blocking DNS
Portainerhttps://192.168.1.100:9443Docker management
Nginx Proxy Managerhttp://192.168.1.100:81Reverse proxy + SSL
File Browserhttp://192.168.1.100:8082Web file manager
Uptime Kumahttp://192.168.1.100:3001Uptime monitoring

Pi-hole Setup

After logging into Pi-hole, set your router’s DNS to 192.168.1.100 so all devices on your network get ad blocking automatically. Alternatively, configure individual devices to use the Pi’s IP as their DNS server.

More Services to Add

Once your base stack is running, you can add more services to docker-compose.yml:

Jellyfin (Media Server)

  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    restart: unless-stopped
    ports:
      - "8096:8096"
    volumes:
      - ./jellyfin/config:/config
      - ./jellyfin/cache:/cache
      - /media:/media

Nextcloud (Cloud Storage)

  nextcloud:
    image: nextcloud:latest
    container_name: nextcloud
    restart: unless-stopped
    ports:
      - "8083:80"
    volumes:
      - ./nextcloud:/var/www/html
    environment:
      SQLITE_DATABASE: nextcloud

Home Assistant (Smart Home)

  homeassistant:
    image: ghcr.io/home-assistant/home-assistant:stable
    container_name: homeassistant
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./homeassistant:/config
    environment:
      TZ: "Asia/Kolkata"

WireGuard (VPN Server)

  wireguard:
    image: linuxserver/wireguard:latest
    container_name: wireguard
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
    ports:
      - "51820:51820/udp"
    environment:
      PUID: 1000
      PGID: 1000
      TZ: "Asia/Kolkata"
      SERVERURL: your.ddns.domain
      PEERS: 3
    volumes:
      - ./wireguard:/config

Step 8: External Access with Cloudflare Tunnels

To access your services from outside your home without opening router ports, use Cloudflare Tunnels:

docker run -d \
  --name cloudflared \
  --restart unless-stopped \
  cloudflare/cloudflared:latest \
  tunnel --no-autoupdate run --token YOUR_TUNNEL_TOKEN

Get your tunnel token from one.dash.cloudflare.com → Networks → Tunnels.

Maintenance and Monitoring

Update All Containers

cd ~/server
docker compose pull
docker compose up -d

Monitor Resource Usage

# System overview
htop

# Docker container stats
docker stats

# Disk usage
df -h

# Temperature (important for Pi!)
vcgencmd measure_temp

Automatic Container Updates with Watchtower

Add this to your docker-compose.yml:

  watchtower:
    image: containrrr/watchtower:latest
    container_name: watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_SCHEDULE: "0 0 4 * * *"

This automatically updates containers daily at 4 AM.

Backup Strategy

Create a simple backup script at ~/backup.sh:

#!/bin/bash
BACKUP_DIR="/media/backup/$(date +%Y-%m-%d)"
mkdir -p "$BACKUP_DIR"

cd ~/server
docker compose down
tar -czf "$BACKUP_DIR/server-data.tar.gz" .
docker compose up -d

echo "Backup completed: $BACKUP_DIR"

Schedule it with cron:

crontab -e
# Add: 0 3 * * 0 /home/youruser/backup.sh

Performance Tips

  1. Use an SSD — The single biggest performance improvement over microSD
  2. Allocate swap space — Even with 8GB RAM, swap prevents OOM kills:
    sudo fallocate -l 2G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
  3. Overclock the Pi 5 — Add to /boot/firmware/config.txt:
    arm_freq=2800
    gpu_freq=900
  4. Monitor temperature — Keep it below 80°C with proper cooling
  5. Use arm64 images — Ensure Docker images support linux/arm64

Security Hardening

  1. Change the default SSH port:
    sudo sed -i 's/#Port 22/Port 2222/' /etc/ssh/sshd_config
    sudo systemctl restart ssh
  2. Install fail2ban to block brute-force attacks:
    sudo apt install -y fail2ban
    sudo systemctl enable fail2ban
  3. Set up a firewall with UFW:
    sudo apt install -y ufw
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow 2222/tcp  # SSH
    sudo ufw allow 53        # DNS (Pi-hole)
    sudo ufw allow 80,443/tcp  # Web
    sudo ufw enable
  4. Use SSH keys instead of passwords (see our SSH key authentication guide)
  5. Keep the system updated with unattended-upgrades

Conclusion

A Raspberry Pi home server gives you complete control over your data and services. With Docker Compose, you can deploy and manage dozens of self-hosted applications with minimal effort. Whether you’re blocking ads network-wide with Pi-hole, streaming media with Jellyfin, or running your own cloud storage with Nextcloud, the Pi handles it all while consuming just 5–15 watts of power.