Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Best Home-Lab Projects to Learn DevOps

By Kokil Thapa | Last reviewed: August 2026

You want to learn DevOps, but reading docs and watching tutorials only gets you so far. The real skill comes from building, breaking, and fixing real systems—exactly what a home lab gives you. Whether you're a developer looking to expand into infrastructure, a sysadmin moving to automation, or a student aiming for your first DevOps role, these projects will force you to solve the same problems you'll face in production. I've used variations of these setups on real client projects—from Laravel deployments to eCommerce platforms—and they work. No cloud credits, no enterprise hardware. Just free tools, a spare laptop or Raspberry Pi, and a weekend.

What hardware do you actually need for a DevOps home lab?

You don't need a rack of servers. A single spare laptop, a Raspberry Pi 4/5, or even an old desktop will work. Here's what I use on most client projects and my own lab:

  • Primary node: Any x86 machine with 8 GB RAM, 120 GB SSD (a 2018+ laptop or NUC works).
  • Secondary nodes: 2–3 Raspberry Pi 4/5 (4 GB RAM each) or old laptops.
  • Network: Gigabit switch + CAT6 cables (or just use your home router).
  • Storage: 1 TB external SSD for backups (optional but recommended).

Total cost if you buy everything new: ~Rs 40,000 (~USD 300). If you repurpose old hardware, it's free. For context, I run a 3-node Kubernetes cluster on two old ThinkPads and a Pi 5—exactly the same setup I use to test deployments for eCommerce clients before pushing to production.

Primary Nodex86, 8 GB RAMNode 2RPi 5, 4 GBNode 3RPi 5, 4 GBNode 4RPi 5, 4 GBGigabit SwitchExternal SSD1 TB Backup
Home-lab hardware topology: 1 primary x86 node, 3 Raspberry Pi nodes, gigabit switch, and external SSD backup

How do you set up a CI/CD pipeline on a home lab?

CI/CD isn't just for cloud providers. You can build a full pipeline on a single machine using GitLab CE (self-hosted) or GitHub Actions runners. Here's how I set it up for a Laravel API project last month:

  1. Install GitLab CE on your primary node:
    # On Ubuntu 24.04 LTS
    sudo apt update && sudo apt install -y curl openssh-server ca-certificates tzdata perl
    curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
    sudo EXTERNAL_URL="http://your-lab-ip" apt install gitlab-ce
    
  2. Register a GitLab Runner:
    # Install runner
    curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
    sudo apt install gitlab-runner
    
    # Register (use the token from GitLab Admin → Runners)
    sudo gitlab-runner register \
      --non-interactive \
      --url "http://your-lab-ip/" \
      --registration-token "PROJECT_REGISTRATION_TOKEN" \
      --executor "shell" \
      --description "home-lab-runner"
    
  3. Create a .gitlab-ci.yml pipeline:
    stages:
      - test
      - build
      - deploy
    
    test:
      stage: test
      script:
        - composer install --prefer-dist --no-progress
        - php artisan test
      only:
        - merge_requests
    
    build:
      stage: build
      script:
        - docker build -t registry.local/laravel-app:$CI_COMMIT_SHORT_SHA .
        - docker push registry.local/laravel-app:$CI_COMMIT_SHORT_SHA
      only:
        - main
    
    deploy:
      stage: deploy
      script:
        - ssh user@node2 "docker pull registry.local/laravel-app:$CI_COMMIT_SHORT_SHA"
        - ssh user@node2 "docker stop laravel-app || true"
        - ssh user@node2 "docker rm laravel-app || true"
        - ssh user@node2 "docker run -d --name laravel-app -p 8000:8000 registry.local/laravel-app:$CI_COMMIT_SHORT_SHA"
      only:
        - main
    
  4. Set up a local Docker registry:
    # On your primary node
    docker run -d -p 5000:5000 --restart=always --name registry registry:2
    

    Then add registry.local to your /etc/hosts pointing to your primary node's IP.

A common mistake I see: developers forget to open port 5000 on the firewall. On Ubuntu:

sudo ufw allow 5000/tcp
DeveloperGitLabRunnerDocker BuildRegistryNode 2SSH Deploy
CI/CD pipeline flow: code commit → GitLab → runner → Docker build → registry → deployment on node2

How do you run Kubernetes on a home lab with limited resources?

You don't need a data center. k3s (a lightweight Kubernetes distro) runs on Raspberry Pis and old laptops. Here's how I deployed it for a WooCommerce client who wanted to test autoscaling:

  1. Install k3s on your primary node (master):
    curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644
    

    This gives you a single-node cluster. To add worker nodes:

  2. Get the node token:
    sudo cat /var/lib/rancher/k3s/server/node-token
    
  3. Join worker nodes:
    curl -sfL https://get.k3s.io | K3S_URL=https://your-master-ip:6443 K3S_TOKEN=your-token sh -
    
  4. Verify the cluster:
    kubectl get nodes
    NAME       STATUS   ROLES    AGE   VERSION
    master     Ready    master   5m    v1.29.4+k3s1
    node2      Ready    <none>   2m    v1.29.4+k3s1
    node3      Ready    <none>   1m    v1.29.4+k3s1
    
  5. Deploy a sample app (Nginx):
    kubectl create deployment nginx --image=nginx
    kubectl expose deployment nginx --port 80 --type=LoadBalancer
    

    k3s includes a built-in LoadBalancer (klipper-lb) that works without cloud providers.

A common gotcha: k3s uses containerd by default, not Docker. If you need Docker:

curl -sfL https://get.k3s.io | sh -s - --docker
Masterk3s serverWorker 1k3s agentWorker 2k3s agentklipper-lbLoadBalancerNginx PodPort 80
k3s cluster topology: 1 master node, 2 worker nodes, and klipper-lb LoadBalancer

What infrastructure-as-code tools should you learn first?

Start with Terraform and Ansible. They solve different problems but work together. Here's how I use them on client projects:

ToolUse CaseExampleWhen to Use
TerraformProvision cloud resources (servers, networks, databases)Create a Linode instance + firewall rulesWhen you need to spin up/down infrastructure
AnsibleConfigure servers (install packages, deploy apps)Install Docker, Nginx, and deploy a Laravel appWhen you need to manage existing servers

Terraform example (Linode):

terraform {
  required_providers {
    linode = {
      source = "linode/linode"
      version = "2.12.0"
    }
  }
}

provider "linode" {
  token = var.linode_token
}

resource "linode_instance" "web" {
  label           = "web-server"
  image           = "linode/ubuntu24.04"
  region          = "ap-west"
  type            = "g6-standard-1"
  authorized_keys = [var.ssh_key]
}

resource "linode_firewall" "web_fw" {
  label = "web-firewall"
  inbound {
    label    = "http"
    action   = "ACCEPT"
    protocol = "TCP"
    ports    = "80"
    ipv4     = ["0.0.0.0/0"]
  }
}

Ansible example (Docker setup):

---
- name: Install Docker
  hosts: all
  become: yes
  tasks:
    - name: Install dependencies
      apt:
        name:
          - apt-transport-https
          - ca-certificates
          - curl
          - software-properties-common
        state: present
        update_cache: yes

    - name: Add Docker GPG key
      apt_key:
        url: https://download.docker.com/linux/ubuntu/gpg
        state: present

    - name: Add Docker repo
      apt_repository:
        repo: deb https://download.docker.com/linux/ubuntu noble stable
        state: present

    - name: Install Docker
      apt:
        name: docker-ce
        state: present

    - name: Add user to docker group
      user:
        name: "{{ ansible_user }}"
        groups: docker
        append: yes

A common mistake: mixing Terraform and Ansible for the same task. Use Terraform for immutable infrastructure (servers, networks) and Ansible for mutable configuration (packages, users).

How do you build a monitoring stack with Prometheus and Grafana?

Monitoring isn't optional—it's how you catch problems before users do. Here's how I set it up for a legal-tech portal that needed 99.9% uptime:

  1. Install Prometheus:
    # Create a prometheus.yml config file
    global:
      scrape_interval: 15s
    
    scrape_configs:
      - job_name: 'prometheus'
        static_configs:
          - targets: ['localhost:9090']
      - job_name: 'node'
        static_configs:
          - targets: ['node1:9100', 'node2:9100']
    
    # Run Prometheus in Docker
    docker run -d -p 9090:9090 -v ./prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
    
  2. Install Node Exporter on all nodes:
    # On each node
    docker run -d -p 9100:9100 --net="host" --pid="host" -v "/:/host:ro,rslave" prom/node-exporter
    
  3. Install Grafana:
    docker run -d -p 3000:3000 --name=grafana grafana/grafana
    

    Default login: admin/admin. Change it immediately.

  4. Add Prometheus as a data source in Grafana:
    • Go to Configuration → Data Sources → Add data source
    • Select Prometheus
    • URL: http://your-prometheus-ip:9090
    • Save & Test
  5. Import a dashboard:
    • Go to Dashboards → Import
    • Use dashboard ID 1860 (Node Exporter Full)
    • Select your Prometheus data source

A common gotcha: Node Exporter needs --net="host" and --pid="host" to collect system metrics. Without these, you'll only see container metrics.

Node 1Node ExporterNode 2Node ExporterPrometheusScrape TargetsGrafanaDashboardsSlackAlerts
Monitoring stack architecture: Prometheus scrapes Node Exporters, Grafana visualizes data, and alerts are sent to Slack

What are the 10 best home-lab projects ranked by learning value?

Not all projects teach you the same skills. Here's my ranked list based on what I've seen working engineers actually need:

  1. CI/CD Pipeline (GitLab CI + Docker)
    • Skills: automation, testing, deployment strategies
    • Why #1: Every DevOps job requires CI/CD. This project forces you to think about build times, artifact storage, and rollback strategies.
  2. Kubernetes Cluster (k3s)
    • Skills: container orchestration, scaling, service discovery
    • Why #2: Kubernetes is the de facto standard. k3s lets you learn the concepts without the complexity of full K8s.
  3. Infrastructure-as-Code (Terraform + Ansible)
    • Skills: reproducibility, version control for infrastructure
    • Why #3: IaC is how modern teams manage servers. This project teaches you to treat infrastructure like code.
  4. Monitoring Stack (Prometheus + Grafana)
    • Skills: observability, alerting, metric visualization
    • Why #4: You can't improve what you don't measure. This project teaches you to instrument applications and set up meaningful alerts.
  5. Log Aggregation (Loki + Promtail)
    • Skills: centralized logging, log querying
    • Why #5: When something breaks, logs are your first line of defense. This project teaches you to collect and analyze logs from multiple sources.
  6. Secrets Management (Vault)
    • Skills: security, credential rotation, access control
    • Why #6: Hardcoded secrets are a security nightmare. This project teaches you to manage credentials properly.
  7. GitOps Workflow (ArgoCD)
    • Skills: declarative infrastructure, continuous delivery
    • Why #7: GitOps is how modern teams manage Kubernetes. This project teaches you to sync your cluster state with Git.
  8. Serverless Functions (OpenFaaS)
    • Skills: event-driven architecture, scaling to zero
    • Why #8: Serverless is growing fast. This project teaches you to build and deploy functions without managing servers.
  9. Multi-Region Deployment (Linode + Terraform)
    • Skills: high availability, disaster recovery
    • Why #9: Real systems need redundancy. This project teaches you to deploy across multiple regions.
  10. Home Automation (Home Assistant + MQTT)
    • Skills: IoT, event streaming, edge computing
    • Why #10: Fun and practical. This project teaches you to work with sensors and real-time data.

A common mistake: jumping straight to Kubernetes without mastering CI/CD first. The projects are ordered for a reason—each builds on the last.

CI/CDKubernetesIaCMonitoringLogsSecretsGitOpsServerlessMulti-RegionIoT
DevOps project learning progression: CI/CD → Kubernetes → IaC → Monitoring → Logs → Secrets → GitOps → Serverless → Multi-Region → IoT

How do you troubleshoot common home-lab problems?

Your lab will break. That's the point. Here's how I fix the most common issues I see on client projects and my own lab:

ProblemSymptomsDiagnosisFix
Docker containers won't startPort already in use, permission denieddocker logs <container>, ss -tulnp | grep <port>Kill the conflicting process or change the port
k3s nodes not joiningkubectl get nodes shows nodes as NotReadyjournalctl -u k3s -f on the worker nodeCheck firewall rules (sudo ufw allow 6443/tcp), verify token
Terraform state mismatchTerraform wants to destroy/create resources you didn't changeterraform plan shows unexpected changesCheck for manual changes, use terraform import to sync state
Prometheus scrape failuresTargets show "DOWN" in Prometheus UIcurl http://<target>:9100/metrics failsCheck Node Exporter logs (docker logs node-exporter), verify network connectivity
GitLab CI jobs stuckJobs show "pending" forevergitlab-runner verify, gitlab-runner listRestart the runner (sudo systemctl restart gitlab-runner), check for resource limits
Ansible playbook failsPlaybook stops with "unreachable" or "failed" tasksansible -m ping all, ansible-playbook --check playbook.ymlCheck SSH connectivity, verify inventory file, use --limit to test on one host

A common mistake: assuming the problem is with the tool, not your configuration. 90% of issues I see are caused by:

  • Incorrect file permissions (chmod 644 vs chmod 600)
  • Firewall blocking ports (sudo ufw status)
  • Resource limits (check free -m and df -h)
  • Version mismatches (always pin versions in config)

Start building your DevOps skills today

You don't need a cloud account or expensive hardware to learn DevOps. Pick one project from this list—CI/CD is the best starting point—and spend a weekend building it. Break it, fix it, then move to the next one. The skills you learn will apply directly to real-world systems, whether you're deploying a Laravel application, managing an eCommerce platform, or building infrastructure for a startup.

When you're ready to take your skills to the next level, I offer DevOps consulting and training for teams and individuals. Let's build something real together.

Frequently Asked Questions

Start with these five battle-tested projects that cover the full DevOps lifecycle: 1) A three-node Kubernetes cluster (k3s v1.30) on Raspberry Pi 5 or cheap x86 mini-PCs running Ubuntu 24.04 LTS, 2) A GitLab CE instance with CI/CD pipelines that auto-deploy a Laravel 12 app to a staging VM, 3) A Prometheus + Grafana stack monitoring your home network and lab servers, 4) An Ansible playbook that provisions a fresh Ubuntu 24.04 server with PHP 8.4, Nginx, and MySQL 8.4, and 5) A Terraform configuration that spins up a t3.micro EC2 instance on AWS with a VPC, security groups, and a WordPress site. Each project forces you to touch infrastructure-as-code, configuration management, observability, and deployment automation—exactly what you’ll do in production.

A minimal viable lab costs Rs 25,000–40,000 (~USD 190–300). You’ll need: a Raspberry Pi 5 (Rs 12,000), a 64 GB microSD card (Rs 1,500), a cheap 5-port Gigabit switch (Rs 3,000), three Cat6 cables (Rs 500), and a used ThinkPad T450 (Rs 15,000) running Ubuntu 24.04 as your control node. Skip the Pi if you already have a spare x86 machine; a single NUC or old desktop with 16 GB RAM and a 256 GB SSD is enough to run k3s, GitLab, and monitoring side-by-side. Cloud credits (AWS/GCP) are free for the first year, so you can extend the lab to the cloud without extra cost.

Yes, but you’ll miss critical troubleshooting skills. Use a cloud-only lab with AWS Free Tier (t3.micro instances), GCP’s always-free f1-micro, or Oracle Cloud’s ARM VMs. Spin up a Vagrant box (ubuntu/jammy64) on your laptop with 4 GB RAM and 20 GB disk—enough to run Docker, Ansible, and a single-node k3s cluster. The trade-off: you won’t experience real hardware failures, network latency, or disk I/O bottlenecks that surface only in physical labs. For observability practice, install Prometheus + Grafana inside the VM and monitor its own metrics.

Ubuntu Server 24.04 LTS. It’s the default choice for cloud providers, has long-term support until 2034, and ships with kernel 6.8, which includes eBPF support for observability tools like Cilium and Pixie. The installer offers a minimal “cloud-init” image that weighs only 500 MB, leaving more disk for containers and VMs. If you prefer immutable systems, try Fedora Server 40 or Flatcar Container Linux (formerly CoreOS), but expect fewer community tutorials and package availability for tools like k3s or GitLab.

Use k3s v1.30 on three nodes (one control plane, two workers). Install Ubuntu 24.04 on each, disable swap (`sudo swapoff -a`), and run the k3s installer: `curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644`. On the control plane, retrieve the join token (`sudo cat /var/lib/rancher/k3s/server/node-token`) and run the same installer on workers with `--server https://:6443 --token `. Verify with `kubectl get nodes`; expect three Ready nodes in under five minutes. For storage, install Longhorn (`kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.6.0/deploy/longhorn.yaml`) to turn local disks into a distributed block store.

GitLab CE + CI/CD pipelines. Install GitLab on a dedicated VM (Ubuntu 24.04, 4 GB RAM, 50 GB disk) using the official Omnibus package: `sudo apt install gitlab-ce`. Create a `.gitlab-ci.yml` file that builds a Docker image, pushes it to GitLab Container Registry, and deploys to your k3s cluster using `kubectl apply -f k8s/`. For Laravel apps, add a `deploy.php` script and use Deployer 7 to push code to a staging VM. The pipeline runs on every `git push`, giving you instant feedback—exactly like production CI/CD.

Install Prometheus + Grafana + Node Exporter. On your control node, run `helm repo add prometheus-community https://prometheus-community.github.io/helm-charts` and deploy the stack: `helm install prometheus prometheus-community/kube-prometheus-stack --namespace monitoring --create-namespace`. This gives you Prometheus scraping metrics, Grafana dashboards (use the default “Node Exporter Full” dashboard), and Alertmanager for notifications. For logs, add Loki (`helm install loki grafana/loki`) and configure Grafana to query it. Set up alerts for high CPU, disk full, or Kubernetes pod crashes—realistic scenarios you’ll face in production.

Use restic + Backblaze B2 or a local NAS. Install restic (`sudo apt install restic`) and initialize a repository: `restic -r b2:bucket-name:path init`. Create a backup script that dumps MySQL (`mysqldump -u root -p --all-databases > all-dbs.sql`), stops critical containers, and runs `restic backup /home /etc /var/lib/docker`. Schedule it with cron (`0 2 * /usr/local/bin/backup.sh`). For Kubernetes, use Velero (`velero install --provider aws --plugins velero/velero-plugin-for-aws:v1.12.0 --bucket --backup-location-config region=auto --snapshot-location-config region=auto --secret-file ./credentials-velero`) to back up cluster state and persistent volumes.

Treat it like a production environment. Enable UFW (`sudo ufw allow 22,80,443,6443/tcp`), install fail2ban (`sudo apt install fail2ban`), and rotate SSH keys every 90 days. For Kubernetes, enable RBAC (`k3s server --disable traefik --disable servicelb --kube-apiserver-arg="enable-admission-plugins=NodeRestriction"`), use NetworkPolicy to restrict pod-to-pod traffic, and scan images with Trivy (`trivy image my-app:latest`). For GitLab, enable 2FA, rotate runner tokens, and use Vault or SOPS to encrypt secrets in Git. Never expose the Kubernetes API or GitLab to the internet; use Tailscale or Cloudflare Tunnel for remote access.

GitLab CE. It’s self-hosted, includes a container registry, and has built-in Kubernetes integration. GitHub Actions is cloud-only and lacks a local registry, making it less realistic for on-prem DevOps. Jenkins is powerful but requires heavy configuration (plugins, Groovy scripts) that distracts from learning core DevOps concepts. GitLab’s `.gitlab-ci.yml` is declarative, version-controlled, and mirrors what you’ll use in production. For a three-node k3s cluster, GitLab’s auto-devops feature can deploy Helm charts with zero extra config—ideal for beginners.

Start with `kubectl describe pod ` and look for events at the bottom. Check logs: `kubectl logs --previous` (for crashed pods). If the pod is CrashLoopBackOff, exec into it: `kubectl exec -it -- sh` and run `ps aux` or `journalctl -xe`. For network issues, use `kubectl get endpoints` and `kubectl run -it --rm debug --image=busybox --restart=Never -- sh` to test connectivity. If the node is NotReady, SSH into it and check `journalctl -u k3s` or `dmesg` for hardware errors. Always verify PersistentVolumeClaims (`kubectl get pvc`)—a common gotcha in home-labs with limited disk space.

Write a playbook that provisions a fresh Ubuntu 24.04 VM with PHP 8.4, Nginx, MySQL 8.4, and a Laravel 12 app. Start with a single playbook (`provision.yml`) that installs packages (`apt`), configures services (`systemd`), and deploys code (`git`). Use roles (`ansible-galaxy init php`) to modularize tasks. Test with `ansible-playbook -i inventory.ini provision.yml --check` (dry run) and `ansible-playbook -i inventory.ini provision.yml --diff` (show changes). For realism, add handlers (`restart nginx`) and templates (`nginx.conf.j2`). Store secrets in Ansible Vault (`ansible-vault encrypt secrets.yml`)—a pattern you’ll use in production.

Use Terraform to manage cloud resources alongside your physical lab. Write a configuration (`main.tf`) that creates a VPC, security groups, and a t3.micro EC2 instance on AWS. Install the AWS provider (`terraform init`) and run `terraform apply`. For hybrid setups, use the `local` provider to generate Ansible inventory files or Kubernetes manifests. Store state remotely (`terraform { backend "s3" { bucket = "my-lab-state" key = "terraform.tfstate" } }`) to avoid losing it. For local VMs, use the `libvirt` provider to spin up KVM guests—ideal for testing multi-node clusters without cloud costs.

Use Markdown + MkDocs. Create a `docs/` directory in your project repo and write `index.md`, `setup.md`, `troubleshooting.md`, and `architecture.md`. Install MkDocs (`pip install mkdocs`) and run `mkdocs serve` to preview. For diagrams, use Mermaid.js (`mermaid graph TD A[GitLab] -->|CI/CD| B[k3s Cluster]`). Store the docs in the same repo as your code—this mirrors production DevOps where documentation lives alongside infrastructure-as-code. For Kubernetes, add `kubectl explain` snippets (`kubectl explain pod.spec.containers`) to help future you debug.

Follow the same process as production: test in staging, backup, and roll back if needed. For Kubernetes, upgrade k3s one minor version at a time (`k3s server --cluster-init --kubernetes-version v1.29.4`). For GitLab, use the Omnibus upgrade guide (`sudo apt update && sudo apt install gitlab-ce`). For Ansible, test playbooks in a Vagrant VM before running them on production nodes. Always snapshot VMs or back up restic repositories before major changes. Keep a `CHANGELOG.md` in your repo to track versions and upgrade steps—this habit saves hours when you revisit the lab months later.

Share this article

Quick Contact Options
Choose how you want to connect me: