{"id":47619217,"url":"https://github.com/joe-mccarthy/homelab","last_synced_at":"2026-04-12T16:01:24.487Z","repository":{"id":278008253,"uuid":"933870955","full_name":"joe-mccarthy/homelab","owner":"joe-mccarthy","description":"Build and manage a docker swarm cluster using ansible on Raspberry Pis","archived":false,"fork":false,"pushed_at":"2026-03-31T12:43:54.000Z","size":595,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-02T07:40:43.654Z","etag":null,"topics":["ansible","automation","docker","docker-cluster","docker-compose","docker-swarm","documentation","home-assistant","homelab","how-to","portainer","raspberry-pi","raspberrypi","traefik"],"latest_commit_sha":null,"homepage":"","language":"Jinja","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joe-mccarthy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"joe-mccarthy","buy_me_a_coffee":"joe_mccarthy"}},"created_at":"2025-02-16T21:40:26.000Z","updated_at":"2026-03-28T13:29:22.000Z","dependencies_parsed_at":"2025-02-17T14:33:28.521Z","dependency_job_id":"ba8a2870-c355-4de5-baec-2be3cc15089d","html_url":"https://github.com/joe-mccarthy/homelab","commit_stats":null,"previous_names":["joe-mccarthy/home-services","joe-mccarthy/home-lab","joe-mccarthy/homelab"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/joe-mccarthy/homelab","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joe-mccarthy%2Fhomelab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joe-mccarthy%2Fhomelab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joe-mccarthy%2Fhomelab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joe-mccarthy%2Fhomelab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joe-mccarthy","download_url":"https://codeload.github.com/joe-mccarthy/homelab/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joe-mccarthy%2Fhomelab/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31668049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T17:19:37.612Z","status":"online","status_checked_at":"2026-04-11T02:00:05.776Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","automation","docker","docker-cluster","docker-compose","docker-swarm","documentation","home-assistant","homelab","how-to","portainer","raspberry-pi","raspberrypi","traefik"],"created_at":"2026-04-01T21:53:55.119Z","updated_at":"2026-04-11T03:34:44.154Z","avatar_url":"https://github.com/joe-mccarthy.png","language":"Jinja","funding_links":["https://github.com/sponsors/joe-mccarthy","https://buymeacoffee.com/joe_mccarthy"],"categories":[],"sub_categories":[],"readme":"# Home Lab\n[![Issues and PRs](https://img.shields.io/github/issues/joe-mccarthy/homelab?style=flat-square)](https://github.com/joe-mccarthy/homelab/issues)\n[![Release](https://img.shields.io/github/v/release/joe-mccarthy/homelab?style=flat-square)](https://github.com/joe-mccarthy/homelab/releases)\n[![Last commit](https://img.shields.io/github/last-commit/joe-mccarthy/homelab?style=flat-square)](https://github.com/joe-mccarthy/homelab/commits/main)\n[![License](https://img.shields.io/github/license/joe-mccarthy/homelab?style=flat-square)](LICENSE)\n[![ansible-lint](https://img.shields.io/github/actions/workflow/status/joe-mccarthy/homelab/ansible-linter.yml?style=flat-square\u0026label=ansible%20lint)](https://github.com/joe-mccarthy/homelab/actions/workflows/ansible-linter.yml)\n\n\nThe purpose of this repository is to create and manage a simple [home lab](https://linuxhandbook.com/homelab/) built around clusters of [Raspberry Pi's](https://www.raspberrypi.com/) using [Docker Swarm](https://docs.docker.com/engine/swarm/) for container deployment and management. The primary tool for managing the home lab is [Ansible](https://docs.ansible.com/ansible/latest/index.html). \n\nThis repository is designed to help you learn, test, and experiment with deploying and managing services in a clustered environment. It provides a structured approach to setting up a home lab, automating deployments, and maintaining the cluster.\n\nFor a service-by-service deployment catalog, see [deployments/README.md](deployments/README.md).\n\n\u003e **⚠️ Warning**  \n\u003e All examples within this repository are for testing, learning, and development purposes and should not be used for production environments.\n\n---\n\n## Hardware\n\nThis home lab is built entirely using Raspberry Pi devices. The current setup includes:\n\n- **8 Raspberry Pi 4s** with 8GB of memory, each with a 64GB SD card.\n- **1 Raspberry Pi 5** with 8GB of memory and a 2TB NVMe drive connected via PCIe using a [Pimoroni NVMe base](https://shop.pimoroni.com/products/nvme-base?variant=41219587178579).\n- **PoE Hats** for each Raspberry Pi 4 to simplify power and networking.\n- **8-Port PoE Switch** to power and connect all devices.\n\nThe cluster is designed to be flexible, with services distributed across nodes. However, one node must host the [NFS](https://en.wikipedia.org/wiki/Network_File_System) server for persistent storage. In this setup, the Raspberry Pi 5 with the NVMe drive serves as the NFS server.\n\n### Why Persistent Storage?\n\nPersistent storage is critical for:\n- Allowing services to move between nodes without losing data.\n- Supporting deployments like [Home Assistant](https://www.home-assistant.io/) that perform frequent writes, which can quickly wear out SD cards.\n\n---\n\n## Authentication, Hosts, and Vaults\n\nBefore deploying services to Docker Swarm, the cluster must be defined, machines set up, and sensitive variables secured.\n\n### Defining Hosts\n\nAnsible uses an inventory file to define the hosts it manages. In this project, the inventory is referenced externally using [Ansible configuration](https://docs.ansible.com/ansible/latest/reference_appendices/config.html). A ready-to-use example is provided at [`inventory.example.yml`](inventory.example.yml). Copy it and populate it with your own IPs and hostnames:\n\n```bash\ncp inventory.example.yml inventory.yml\n```\n\nThe inventory defines three Ansible groups: `nfs_servers` (the NFS host, which can double as a Swarm manager), `manager` (all Swarm manager nodes), and `docker` (Swarm worker nodes). Both `manager` and `docker` are children of `cluster`, which lets maintenance playbooks target all nodes at once. The example uses Norse mythology names — `odin` as the primary manager and NFS server, `thor` and `loki` as additional managers, and `freyr`, `tyr`, `heimdall`, `baldur`, `frigg`, and `skadi` as workers.\n\nIt's important to consider the number of managers you have for the size and reliability of the cluster[^1].\n\n### Setting Up Machines\n\nAll nodes in the cluster have had a similar installation of Ubuntu 24.10 along with a hostname to match what their role will become within the cluster. \n\nOnce the machine has been booted up for the first time, then a static IP address is assigned to it from my router. Your configuration, IP address ranges, and networking hardware might vary and limit what you're able to do with networking. However, hostnames should in most cases be enough to get the cluster running.\n\nOther than this configuration, all other management will be done through Ansible.\n\n### Keeping Secrets Secure with Vaults\n\nWithin this repository, there are deployments and configurations that require sensitive information in order to work. For example, the Cloudflare API token for setting the Dynamic DNS records that you wish. For this reason, the use of [Ansible Vault](https://docs.ansible.com/ansible/latest/vault_guide/index.html) is leaned on in order to keep these sensitive credentials safe.\n\nA complete reference of every vault variable expected across all deployments is documented in [`vault.template.yml`](vault.template.yml) at the root of this repository. Copy it, fill in your real values, and encrypt it:\n\n```bash\ncp vault.template.yml vault.yml\n# edit vault.yml with real values\nansible-vault encrypt vault.yml\n```\n\nThe variables are referenced within each deployment's `group_vars/all.yml`, which maps vault lookups to the variables used in templates. If you prefer not to use vaults, you can replace the vault lookup with your actual data directly — for example:\n\n```yml\n# With vault (recommended)\ncf_token: \"{{ vault_cf_token }}\"\n\n# Without vault (keep the file private)\ncf_token: your-actual-token\n```\n\n#### Domain Name Information\n\nThere is one other vault variable used in the inventory itself — the base domain for all proxy routing. This is consumed by [Traefik](https://doc.traefik.io/traefik/) to define what it listens for, where it forwards traffic, and which domain to issue certificates for. It is documented in [`vault.template.yml`](vault.template.yml) under `vault.shared.general.domain`.\n\n```yml\ngeneral:\n   domain: \"example.com\"\n```\n\nThis value can sit in `all.vars` of your `inventory.yml` as plain text, or be encrypted using [Ansible Vault Strings](https://docs.ansible.com/ansible/latest/vault_guide/vault_encrypting_content.html#encrypting-individual-variables-with-ansible-vault) — sharing less is always better.\n\n---\n\n## Getting Started\n\nAssuming that you've created an `inventory.yml` from [`inventory.example.yml`](inventory.example.yml) as described above, along with actually installing an Operating System and setting up the initial Hardware, I recommend the following steps.\n\n1. **Create an SSH Key Pair**:\n   - Generate a private/public key pair for the cluster:\n     ```bash\n     ssh-keygen -t rsa -b 4096 -C \"your_email@example.com\" -f ~/.ssh/homelab\n     ```\n   - Place the private key in your `.ssh` folder.\n\n2. **Set Up Machines**:\n   - Use the [set-up-machine](maintenance/set-up-machine/README.md) playbook to prepare all nodes in the cluster. This playbook installs updates, required packages, and copies the public SSH key to each node.\n\n3. **Create the Cluster**:\n   - Once the machines are ready, initialize Docker Swarm using the [create-swarm](docker-swarm/README.md) playbook.\n\n4. **Deploy Core Services**:\n   - Deploy essential services like Traefik, Portainer, and Dynamic DNS using the [core-deployments](deployments/core-deployments/README.md) playbook.\n  - Use the [deployments catalog](deployments/README.md) for the full list of available services and per-service documentation.\n\n---\n\n## Contributions\n\nI'm one person, who has learned this stuff and developed this for their own use. I don't pretend to be an expert; I'm just sharing what I've learned. That being said, if you see any issues, or ways to do things better, then please raise an issue and pull request to make everything better for everyone. Any contributions you make are greatly appreciated.\n\nIf you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag \"enhancement\".\n\nDon't forget to give the project a star! Thanks again!\n\n1. Fork the Project\n1. Create your Feature Branch (git checkout -b feature/AmazingFeature)\n1. Commit your Changes (git commit -m 'Add some AmazingFeature')\n1. Push to the Branch (git push origin feature/AmazingFeature)\n1. Open a Pull Request\n\n---\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n[^1]: An odd number N of manager nodes in the cluster tolerates the loss of at most (N-1)/2 managers. Docker recommends a maximum of seven manager nodes for a swarm.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoe-mccarthy%2Fhomelab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoe-mccarthy%2Fhomelab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoe-mccarthy%2Fhomelab/lists"}