279 lines
7.1 KiB
Markdown
279 lines
7.1 KiB
Markdown
# nbops-ansible
|
|
|
|
## nbops
|
|
#### Infrastructure as Code for notBoris' Homelab
|
|
|
|
nbops is the central operations repository for my hosted infrastructure, containing everything required to provision, configure, and maintain my virtual machines and services. The goal is to treat my infrastructure as code for reproducibility and automation from source control, while having minimal manual intervention.
|
|
|
|
## About
|
|
|
|
nbops-ansible contains the configuration management layer of the nbops platform.
|
|
|
|
Every virtual machine begins life as a standardised Debian 13 GenericCloud template, provisioned by Proxmox and bootstrapped with Cloud-Init. Once the operating system has completed its initial configuration, the host runs ansible-pull against this repository to configure itself according to its assigned role.
|
|
|
|
A freshly created virtual machine should require little more than a hostname, network configuration and SSH key before automatically configuring itself into a production-ready host.
|
|
|
|
|
|
# Design Philosophy
|
|
|
|
This repository follows a layered approach where each component has a clearly defined responsibility.
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A[GitHub: nbops-ansible] --> B[Proxmox VE]
|
|
B --> C[Debian 13 GenericCloud Template]
|
|
C --> D[Clone VM]
|
|
D --> E[Cloud-Init Bootstrap]
|
|
E --> F[ansible-pull]
|
|
F --> G[Apply Base Roles]
|
|
G --> H[Apply Service Roles]
|
|
H --> I[Docker Compose]
|
|
I --> J[Running Services]
|
|
```
|
|
|
|
## Layer Responsibilities
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
P[Proxmox VE<br/>VM lifecycle<br/>storage<br/>networking]
|
|
D[Debian 13<br/>GenericCloud<br/>minimal OS]
|
|
C[Cloud-Init<br/>identity<br/>network<br/>bootstrap]
|
|
A[Ansible<br/>desired state<br/>roles<br/>configuration]
|
|
DC[Docker Compose<br/>service runtime]
|
|
S[Applications<br/>actual workloads]
|
|
|
|
P --> D --> C --> A --> DC --> S
|
|
```
|
|
|
|
# Repository Structure
|
|
|
|
.
|
|
├── inventories/
|
|
│ ├── production/
|
|
│ └── development/
|
|
│
|
|
├── playbooks/
|
|
│
|
|
├── roles/
|
|
│ ├── base/
|
|
│ ├── docker/
|
|
│ ├── ssh/
|
|
│ ├── ufw/
|
|
│ ├── mtls/
|
|
│ ├── monitoring/
|
|
│ ├── traefik/
|
|
│ ├── authentik/
|
|
│ ├── immich/
|
|
│ ├── gitea/
|
|
│ ├── arr/
|
|
│ ├── ocis/
|
|
│ └── pterodactyl/
|
|
│
|
|
├── group_vars/
|
|
├── host_vars/
|
|
├── templates/
|
|
├── files/
|
|
├── scripts/
|
|
└── docs/
|
|
|
|
As the infrastructure grows, additional functionality should be implemented as new roles rather than modifying existing ones wherever practical.
|
|
|
|
|
|
# Configuration Workflow
|
|
|
|
Cloud-Init is intentionally lightweight.
|
|
|
|
Its responsibility is limited to preparing the operating system by configuring:
|
|
|
|
* Hostname
|
|
* Networking
|
|
* DNS
|
|
* Users
|
|
* SSH
|
|
* Docker
|
|
* Firewall
|
|
* Internal CA trust
|
|
* Base packages
|
|
|
|
Once complete, Cloud-Init hands over to Ansible.
|
|
|
|
Ansible is responsible for configuring and maintaining the desired state of every machine for the remainder of its lifecycle.
|
|
|
|
# Roles
|
|
|
|
The repository is built around reusable Ansible roles; every server receives a common baseline before additional service-specific roles are applied.
|
|
|
|
## Core Roles
|
|
|
|
* base
|
|
* docker
|
|
* ssh
|
|
* ufw
|
|
* mtls
|
|
* monitoring
|
|
* updates
|
|
|
|
## Service Roles
|
|
|
|
* traefik
|
|
* authentik
|
|
* gitea
|
|
* Pelican
|
|
* etc..
|
|
|
|
This approach allows new services to inherit the same security, logging and operating system configuration while remaining independent from one another.
|
|
|
|
# Operating System Standard
|
|
|
|
Unless otherwise required, every virtual machine deployed by nbops follows the same baseline.
|
|
|
|
* Debian 13 (Trixie)
|
|
* GenericCloud image
|
|
* UEFI (OVMF)
|
|
* Q35 machine type
|
|
* VirtIO networking
|
|
* VirtIO SCSI storage
|
|
* QEMU Guest Agent
|
|
* Docker Engine
|
|
* Docker Compose Plugin
|
|
* Chrony
|
|
* UFW
|
|
* SSH key authentication only
|
|
|
|
Standardising the operating system significantly reduces maintenance overhead and configuration drift across the environment.
|
|
|
|
# Infrastructure Principles
|
|
|
|
The following principles guide every decision made within this repository.
|
|
|
|
* Everything should be reproducible.
|
|
* Everything should be version controlled.
|
|
* Manual configuration should be avoided.
|
|
* Infrastructure should be disposable rather than unique.
|
|
* Security should be built into the baseline.
|
|
* Applications should remain isolated from the operating system wherever possible.
|
|
* Configuration should be modular and reusable.
|
|
|
|
# Future Goals
|
|
|
|
Planned work includes:
|
|
|
|
* Automated Debian template creation
|
|
* Cloud-Init template generation
|
|
* Automated certificate management
|
|
* Secret management
|
|
* Monitoring and alerting
|
|
* Backup automation
|
|
* Configuration validation
|
|
* Disaster recovery testing
|
|
* Multi-node infrastructure support
|
|
|
|
# Contributing
|
|
|
|
This repository is primarily maintained for my own homelab, but the techniques and playbooks may be useful to others building similar self-hosted environments.
|
|
|
|
Suggestions, improvements and ideas are always welcome.
|
|
|
|
# License
|
|
|
|
Unless otherwise stated, all code within this repository is released under the MIT License.
|
|
# nbops-ansible
|
|
|
|
Ansible repository for a reproducible Proxmox-based Infrastructure as Code
|
|
platform using Debian 13 GenericCloud, Cloud-Init, Docker Engine, Docker Compose,
|
|
and `ansible-pull`.
|
|
|
|
## Model
|
|
|
|
```text
|
|
Proxmox
|
|
-> Debian 13 GenericCloud template
|
|
-> clone
|
|
-> Cloud-Init
|
|
-> ansible-pull
|
|
-> base roles
|
|
-> service roles
|
|
-> Docker Compose
|
|
```
|
|
|
|
Cloud-Init handles Day 0 bootstrap only. Ansible owns Day 1 onward state.
|
|
|
|
## Layout
|
|
|
|
- `inventories/`: production and development inventories
|
|
- `playbooks/`: site and pull entrypoints
|
|
- `roles/`: reusable core and application roles
|
|
- `group_vars/`: shared defaults
|
|
- `host_vars/`: per-VM overrides
|
|
- `templates/`: Cloud-Init and shared templates
|
|
- `scripts/`: local helper scripts
|
|
- `docs/`: operational notes
|
|
|
|
## Roles
|
|
|
|
Core roles:
|
|
|
|
- `base`
|
|
- `ssh`
|
|
- `ufw`
|
|
- `updates`
|
|
- `docker`
|
|
- `mtls`
|
|
- `monitoring`
|
|
|
|
Application roles:
|
|
|
|
- `traefik`
|
|
- `authentik`
|
|
- `immich`
|
|
- `gitea`
|
|
- `ocis`
|
|
- `pterodactyl`
|
|
- `arr`
|
|
|
|
Enable roles per host with `nbops_roles`.
|
|
|
|
```yaml
|
|
nbops_roles:
|
|
- base
|
|
- ssh
|
|
- ufw
|
|
- updates
|
|
- docker
|
|
- mtls
|
|
- monitoring
|
|
- traefik
|
|
```
|
|
|
|
## VM Topology
|
|
|
|
Every VM is expected to run Docker. Put `docker` in `nbops_roles` for each VM.
|
|
|
|
The edge VM normally runs `traefik` and `authentik`, with Traefik publishing
|
|
ports `80` and `443`. Downstream VMs can run their own internal Traefik and set
|
|
`nbops_service_routing_mode: traefik` so applications register with Traefik
|
|
instead of exposing individual host ports.
|
|
|
|
See `host_vars/edge.yml.example`, `host_vars/downstream.yml.example`, and
|
|
`docs/topology.md`. The full Docker service list is in `docs/service-catalog.md`.
|
|
|
|
## Bootstrap
|
|
|
|
Render `templates/cloud-init-user-data.yml.j2` with host variables and pass it to
|
|
Proxmox as user-data. The template installs baseline packages, Docker from
|
|
Docker's official Debian repository, configures UFW and SSH, creates `/srv` and
|
|
PKI directories, and executes `ansible-pull`.
|
|
|
|
## Secrets
|
|
|
|
Secrets are intentionally excluded. Do not commit passwords, API keys,
|
|
certificates, private keys, or generated `.env` files. Use Ansible Vault, SOPS,
|
|
Vault, or Smallstep-backed issuance when introducing real secret material.
|
|
|
|
## Validation
|
|
|
|
```sh
|
|
ansible-galaxy collection install -r requirements.yml
|
|
scripts/check.sh
|
|
```
|