Tutorial

Building Your First Homelab with a VPS: A Complete Guide

Learn how to set up a personal homelab using VPS hosting. Host your own cloud storage, media server, VPN, and more. Perfect for learning self-hosting and gaining sysadmin skills.

Published:
Data notes

Building Your First Homelab with a VPS: A Complete Guide

A homelab is the perfect way to learn system administration, host your own services, and take control of your digital life. This guide will show you how to build a powerful homelab using a VPS.

What is a Homelab?

A homelab is a personal computing environment where you can:

  • Experiment with different technologies
  • Host your own services (email, cloud storage, media)
  • Learn Linux and system administration
  • Develop and test applications
  • Gain real-world IT skills

Why Use a VPS for Your Homelab?

Advantages over physical hardware:

  • ✅ No electricity costs at home
  • ✅ No noise or heat in your room
  • ✅ Remote access from anywhere
  • ✅ Professional internet connection
  • ✅ Easy to scale up/down
  • ✅ Starting at $5/month

When to choose physical hardware:

  • Need massive storage (>1TB)
  • Want maximum privacy
  • Have unreliable internet at home
  • Enjoy building hardware

Choosing Your VPS for Homelab

ServiceMinimumRecommended
Basic Services1 vCPU, 1GB RAM2 vCPU, 2GB RAM
Media Server2 vCPU, 2GB RAM4 vCPU, 4GB RAM
Multiple Docker Containers2 vCPU, 4GB RAM4 vCPU, 8GB RAM
Full Homelab4 vCPU, 8GB RAM6+ vCPU, 16GB+ RAM

Best VPS Providers for Homelabs

  1. Hetzner - Best value for storage, Germany
  2. Contabo - Huge storage options, budget-friendly
  3. DigitalOcean - Best documentation, easy to use
  4. Linode - Good balance of performance and price
  5. Hetzner Auction - Get dedicated servers cheap

Initial Server Setup

Step 1: Install Docker & Docker Compose

# Update system
sudo apt update && sudo upgrade -y

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Add your user to docker group
sudo usermod -aG docker $USER

# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# Verify installation
docker --version
docker-compose --version

Step 2: Install Portainer (Docker Management UI)

docker volume create portainer_data
docker run -d \
  -p 9000:9000 \
  --name portainer \
  --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:latest

Access at: http://your-server-ip:9000

Step 3: Install Nginx Proxy Manager

docker run -d \
  --name npm \
  -p 80:80 \
  -p 443:443 \
  -p 81:81 \
  --restart always \
  -v npm_data:/data \
  -v npm_letsencrypt:/etc/letsencrypt \
  jc21/nginx-proxy-manager:latest

Access at: http://your-server-ip:81 (admin@example.com / changeme)

Essential Homelab Services to Set Up

1. Cloud Storage: Nextcloud

Why: Google Drive/Dropbox alternative with full control

version: '3'
services:
  nextcloud-db:
    image: mariadb:10.6
    container_name: nextcloud-db
    restart: always
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
      MYSQL_PASSWORD: your_password

  nextcloud:
    image: nextcloud:latest
    container_name: nextcloud
    restart: always
    ports:
      - "8080:80"
    volumes:
      - nextcloud_data:/var/www/html
      - /path/to/your/files:/data
    environment:
      MYSQL_HOST: nextcloud-db
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
      MYSQL_PASSWORD: your_password
    depends_on:
      - nextcloud-db

2. Media Server: Plex/Jellyfin

Jellyfin (Free, open-source):

version: '3'
services:
  jellyfin:
    image: jellyfin/jellyfin
    container_name: jellyfin
    restart: always
    ports:
      - "8096:8096"
    volumes:
      - jellyfin_config:/config
      - /path/to/movies:/movies
      - /path/to/tvshows:/tvshows
    environment:
      - PUID=1000
      - PGID=1000

3. Password Manager: Bitwarden

version: '3'
services:
  bitwarden:
    image: vaultwarden/server:latest
    container_name: bitwarden
    restart: always
    ports:
      - "8082:80"
    volumes:
      - bitwarden_data:/data
    environment:
      - WEBSOCKET_ENABLED=true

4. VPN Server: WireGuard

version: '3'
services:
  wireguard:
    image: linuxserver/wireguard
    container_name: wireguard
    restart: always
    ports:
      - "51820:51820/udp"
    volumes:
      - wireguard_config:/config
      - /lib/modules:/lib/modules
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=1000
      - PGID=1000
      - SERVERPORT=51820
      - PEERS=1
      - PEERDNS=auto

5. Monitoring: Grafana + Prometheus

version: '3'
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: always
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: always
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin

6. Git Server: Gitea

version: '3'
services:
  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    restart: always
    ports:
      - "3000:3000"
      - "222:22"
    volumes:
      - gitea_data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    environment:
      - USER_UID=1000
      - USER_GID=1000

7. RSS Feed Reader: FreshRSS

version: '3'
services:
  freshrss-db:
    image: postgres:14-alpine
    container_name: freshrss-db
    restart: always
    volumes:
      - freshrss_db:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: freshrss
      POSTGRES_PASSWORD: your_password
      POSTGRES_DB: freshrss

  freshrss:
    image: freshrss/freshrss:latest
    container_name: freshrss
    restart: always
    ports:
      - "8085:80"
    volumes:
      - freshrss_data:/var/www/FreshRSS/data
    environment:
      CRON_MIN: '2,32'

8. Home Automation: Home Assistant

version: '3'
services:
  homeassistant:
    image: homeassistant/home-assistant:latest
    container_name: homeassistant
    restart: always
    ports:
      - "8123:8123"
    volumes:
      - homeassistant_config:/config
    environment:
      - TZ=Your/Timezone

Advanced: Docker Compose for Full Stack

Create a docker-compose.yml with all services:

version: '3.8'

services:
  # Reverse Proxy
  nginx-proxy-manager:
    image: jc21/nginx-proxy-manager:latest
    container_name: npm
    restart: always
    ports:
      - "80:80"
      - "443:443"
      - "81:81"
    volumes:
      - npm_data:/data
      - npm_letsencrypt:/etc/letsencrypt

  # Database for apps
  postgres:
    image: postgres:14-alpine
    container_name: postgres
    restart: always
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: your_secure_password

  # Redis for caching
  redis:
    image: redis:alpine
    container_name: redis
    restart: always
    volumes:
      - redis_data:/data

  # Monitoring Stack
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: always
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: always
    ports:
      - "3000:3000"

volumes:
  npm_data:
  npm_letsencrypt:
  postgres_data:
  redis_data:

Backup Strategy

Automated Backup Script

#!/bin/bash
# /usr/local/bin/backup-homelab.sh

BACKUP_DIR="/backups/homelab"
DATE=$(date +%Y%m%d_%H%M%S)

# Backup Docker volumes
docker run --rm \
  -v nextcloud_data:/data \
  -v "$BACKUP_DIR":/backup \
  alpine tar czf /backup/nextcloud_$DATE.tar.gz /data

# Backup PostgreSQL
docker exec postgres pg_dumpall -U admin > "$BACKUP_DIR/db_$DATE.sql"

# Keep last 7 days
find $BACKUP_DIR -mtime +7 -delete

# Upload to remote storage (optional)
# rclone copy $BACKUP_DIR remote:backups/

Add to crontab:

0 2 * * * /usr/local/bin/backup-homelab.sh

Security Considerations

1. Firewall Configuration

# Allow only necessary ports
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 22/tcp
# Add custom ports for your services
sudo ufw allow 51820/udp  # WireGuard
sudo ufw enable

2. Use a VPN

Access your homelab only through VPN:

  • WireGuard for personal access
  • Tailscale for easy device management

3. SSL Certificates

Use Nginx Proxy Manager for automatic Let’s Encrypt certificates

4. Isolate Services

  • Use Docker networks
  • Separate sensitive services
  • Don’t expose databases publicly

Monitoring Your Homelab

Install Netdata for Real-time Monitoring

bash <(curl -Ss https://my-netdata.io/kickstart.sh)

Access at: http://your-server-ip:19999

Key Metrics to Monitor

  • CPU usage (alert if >80%)
  • RAM usage (alert if >85%)
  • Disk space (alert if >85%)
  • Network traffic
  • Container health

Learning Resources

Practice These Skills

  1. Linux Command Line

    • File management
    • Permissions
    • Process management
    • Log analysis
  2. Docker & Containers

    • Building images
    • Docker Compose
    • Networking
    • Volumes
  3. Networking

    • DNS configuration
    • Reverse proxy
    • SSL/TLS
    • Firewall rules
  4. Databases

    • PostgreSQL
    • MySQL
    • Redis
    • Backup/restore
  5. Web Servers

    • Nginx
    • Apache
    • Load balancing

Homelab Project Ideas

Beginner Level

  • Set up personal cloud storage (Nextcloud)
  • Host a password manager (Bitwarden)
  • Create a personal VPN (WireGuard)
  • Set up monitoring (Grafana)

Intermediate Level

  • Host a Git server (Gitea)
  • Build a media server (Jellyfin)
  • Create a home automation hub (Home Assistant)
  • Set up CI/CD pipeline

Advanced Level

  • Build a Kubernetes cluster
  • Create your own email server
  • Set up distributed storage (MinIO)
  • Build a private cloud (OpenStack)

Cost Optimization

Ways to Save Money

  1. Use Hetzner Auction Servers - Get dedicated servers for €5-15/month
  2. Shared Storage VPS - Contabo offers great value
  3. Scale Down When Not Learning - Pause expensive services
  4. Use Student Discounts - DigitalOcean GitHub Student Pack
  5. Shared Resources - Host multiple services on one VPS

Typical Monthly Costs

SetupMonthly Cost
Basic Homelab (1 VPS)$5-10
Growing Homelab (2-3 VPS)$20-40
Advanced Homelab (Dedicated)$40-80
Full Cloud Replacement$100+

Common Homelab Mistakes

  1. Starting too big - Begin with 1-2 services
  2. No backups - Backup before you need it!
  3. Exposing everything - Use VPN/proxy
  4. Ignoring security - Update regularly
  5. Poor documentation - Document your setup!
  6. Overprovisioning - Start small, scale up

Troubleshooting Common Issues

Container Won’t Start

# Check logs
docker logs container-name

# Check resource usage
docker stats

# Restart container
docker restart container-name

Out of Disk Space

# Check disk usage
df -h

# Find large files
du -sh /var/lib/docker/* | sort -h

# Clean up
docker system prune -a

High CPU Usage

# Check processes
htop

# Check container stats
docker stats

# Restart heavy containers
docker restart heavy-container

Community & Resources

Join the Community

Useful Websites

Next Steps

  1. Start with 1-2 services - Don’t overwhelm yourself
  2. Document everything - Create a personal wiki
  3. Join the community - Ask questions, share knowledge
  4. Experiment freely - That’s what homelabs are for!
  5. Consider privacy - Your data, your rules

VPS: Hetzner CX31 (4 vCPU, 16GB RAM) - ~€25/month

First 5 Services:

  1. Portainer - Management
  2. Nginx Proxy Manager - Reverse proxy
  3. Nextcloud - Cloud storage
  4. Bitwarden - Passwords
  5. Jellyfin - Media server

Estimated Setup Time: 2-3 hours


Ready to start your homelab journey? Use our VPS Finder to find the perfect server for your needs, and check out Best VPS Under $10 for budget-friendly options.

Next steps

Jump into tools and related pages while the context is fresh.

Ready to choose your VPS?

Use our VPS Finder to filter, compare, and find the perfect plan for your needs.